17、React真实DOM和虚拟DOM|缺点和优点|子组件向父组件传值|React组件3个部分|ref可以设置回调函数|为什么不能用index做key|状态提声|跨多级组件传参原理、react之约束|受控组件、setState、生命周期、组件写法、插槽、react.15.6.0.js源码外框、ant-design-pro构成、前端路由及触发条件


一、真实DOM和虚拟DOM|缺点和优点|子组件向父组件传值|React组件3个部分|ref可以设置回调函数|为什么不能用index做key|状态提声|跨多级组件传参原理
1、真实DOM和虚拟DOM
(1)真实DOM,用户每次操作DOM(文档对象模型),都会引起BOM(浏览器对象模型)重新渲染
(2)虚拟DOM,用户每次操作DOM(文档对象模型),都会改变虚拟DOM(堆内存的一个对象),最后一次性地渲染到BOM上。
2、React的缺点和优点  
(1)缺点:
(A)React本身只是一个V,不是一个完整的框架,不是一套完整的框架
(B)需要加上React-Router和React-Redux才能成为一套完整的框架  
(2)优点:
(A)单向数据流动;
(B)虚拟DOM取代物理DOM作为操作对象;
(C)用JSX语法取代HTML模板,在JavaScript里声明式地描述UI。  
3、react子组件向父组件传值
(1)react父组件向子组件传值:属性传参
(2)react子组件向父组件传值:在父组件定义一个函数并绑定父组件的this,在函数体里,将函数的参数赋值给父组件this的一个属性;通过属性传参的方式把这个函数传给子组件。在子组件里,给这个函数传参并执行,实现子组件向父组件传值!
4、React组件3个部分
(1)React组件基本上由3个部分组成——属性(props)、状态(state)以及生命周期方法
(2)React组件一旦接收到的参数(即props)或自身状态有所改变,React组件就会执行相应的生命周期方法,最后渲染。
(3)整个过程完全符合传统组件所定义的组件职责(“属性更新”与“状态改变”)。
(4)以上内容来自《深入React技术栈》第18和30页。
5、ref可以设置回调函数
(1)<input type="text" ref="myInput"/>
this.refs.myInput.value ="22"; //this.$refs.myInput.value ="22"  减少获取dom节点的消耗2)ref属性可以设置为一个回调函数,这也是官方强烈推荐的用法;这个函数执行的时机为:
(3)组件被挂载后,回调函数被立即执行,回调函数的参数为该组件的具体实例。
(4)组件被卸载或者原有的ref属性本身发生变化时,回调也会被立即执行,此时回调函数参数为null,以确保内存泄露。
6、为什么不能用index做key?1)react会根据key来决定是否重新构建该组件
(2)删除和添加操作,会使一个组件使用另一个的组件的index,进而key,进而data
7、状态提声(父组件的函数作为属性传给子组件)
(1)在父组件的constructor中定义状态
(2)在父组件的方法中执行this.setState({})
(3)把父组件的方法作为属性fromParent传给子组件
(4)在子组件的方法中加上this.props.fromParent(e.target.value);
(5)触发子组件的事件,执行子组件的方法,改变父组件的状态
8、跨多级组件传参原理
//祖父组件声明自己支持 context
static childContextTypes = {
  color:PropTypes.string,
  callback:PropTypes.func,
}
//祖父组件提供一个函数,用来返回相应的 context 对象
getChildContext(){
  return{
    color:"red",
    callback:this.callback.bind(this)
  }
}
//孙子组件声明自己需要使用 context
static contextTypes = {
  color:PropTypes.string,
  callback:PropTypes.func,
}

二、约束性组件和非约束性组件(受控组件和非受控组件)
1、约束性组件
<input type="text" value={this.state.name} onChange={this.handleChange} />
handleChange: function(e) {
  this.setState({name: e.target.value});
}
//用户输入内容A>触发onChange事件>handleChange中设置state.name="A"渲染input使他的value变成A
2、非约束性组件
<input type="text" defaultValue="a" />//用户输入A -> input 中显示A 
3、React 把 input,textarea 和 select 三个组件做了抽象和封装,他们有统一的 value 属性 和 onChange 事件。
<input type='text' name='intro' id='intro' value={this.state.email} onChange={this.handleEmail} />
<textarea type='text' name='intro' id='intro' value={this.state.intro} onChange={this.handleIntro} />
<textarea type='text' name='intro' id='intro' value={this.state.intro} onChange={this.handleIntro} />
4、checkbox改变的不是 value ,而是 checked 状态。
<input type='radio' name='gender' checked={this.state.male==='MALE'} onChange={this.handleGender} value='MALE' />
<input type='radio' name='gender' checked={this.state.male==='FEMALE'} onChange={this.handleGender} value='FEMALE' />
handleGender(e){
  this.setState({
    male:e.target.value
  })
}

三、setState
1this.setState接收两种参数
(1)对象+函数(可选):传入的对象浅层合并到新的state中
(2)函数+函数(可选):第一个函数接受两个参数,第一个是当前state,第二个是当前props,该函数返回一个对象,和直接传递对象参数是一样的,就是要修改的state;第二个函数参数是state改变后触发的回调。
2this.setState何时同步何时异步?
(1)异步,由react控制的事件处理程序
(2)同步,react控制之外的事件中调用setState是同步更新的。比如原生js绑定的事件,setTimeout/setInterval等。
(3)大部分开发中用到的都是react封装的事件,比如onChange、onClick、onTouchMove等,这些事件处理程序中的setState都是异步处理的。
3this.setState何时渲染
(1)死循环:this.setState执行时,会根据_compositeLifeCycleState是否为null,来决定是否重新渲染,因此在有的生命周期里,会产生死循环。
(2)只生效一次:this.setState最后执行队列时,先用变量获取并存储state,后来直接修改变量,最后把变量赋值给state,页面渲染。
handleClick() {
  //const count = this.state.count 下面 this.setState 多次执行,但只生效一次。因为似乎存在此行代码。
  this.setState({
    count: count + 1
  })
  this.setState({
    count: count + 1
  })
}

四、React生命周期
1、React15、React16完整生命周期比较
A、实例化
(1)React15之ES5写法:propTypes = {}; getDefaultProps(){return{}};
  //React16之ES6写法:static propTypes = {}; static defaultProps = {}; 2)React15之ES5写法:getInitialState(){return{}};
  //React16之ES6写法:constructor3)React15之ES5写法:componentWillMount//执行setState会合并到初始化状态中;获取从属性生成的状态;此后生命状态会被重置为null;
  //React16之ES6写法:static getDerivedStateFromProps//执行setState会合并到初始化状态中;获取从属性生成的状态4)render//执行setState会发起updateComponent导致-死循环5)componentDidMount//执行setState会导致更新;这是发起异步请求去API获取数据的绝佳时期
B、存在期
(1)React15之ES5写法:componentWillReceiveProps//执行setState会合并到状态中;此后生命状态会被重置为null
  //React16之ES6写法:static getDerivedStateFromProps//执行setState会合并到状态中;2)shouldComponentUpdate//执行setState会发起updateComponent导致-死循环3)React15之ES5写法:componentWillUpdate//执行setState会发起updateComponent导致-死循环
  //React16之ES6写法:此处没有componentWillUpdate4)render//执行setState会发起updateComponent导致-死循环
  //React16之ES6写法:此处新增getSnapshotBeforeUpdate//执行setState会发起updateComponent导致-死循环5)componentDidUpdate//可以有条件地执行setState
C、销毁期
(1)componentWillUnmount//等待页面卸载,改变state没意义。
2、React16生命周期(过渡)
(1)沿用了3个componentWillMount,componentWillReceiveProps,componentWillUpdate
(2)新增了2个getDerivedStateFromProps,getSnapshotBeforeUpdate
(3)在实际项目中,沿用方案和新增方案只能二选一,不能混用
3、React17生命周期(全新)
(1)弃用了3个componentWillMount,componentWillReceiveProps,componentWillUpdate
(2)启用了2个getDerivedStateFromProps,getSnapshotBeforeUpdate
(3)新增了1个componentDidCatch(处理错误)
来源:https://blog.csdn.net/liuqiao0327/article/details/107297106

五、React组件写法
1、React15.6.1版组件之ES5写法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React实例</title>
<script src="https://lib.baomitu.com/react/15.6.1/react.js"></script>
<script src="https://lib.baomitu.com/react/15.6.1/react-dom.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
var Button = React.createClass({
  setNewNumber(number,event) {
    this.setState({number: this.state.number + 1})
  },
  getDefaultProps() {
    return { name: "计数器" };
  },
  getInitialState() {
    return{number: 0};
  },
  render() {
    return (
      <div>
        <button onClick = {this.setNewNumber.bind(null,this.state.number,event)}>点击{this.props.name}</button>
        <Text myNumber = {this.state.number}></Text>
      </div>
    );
  }
})
var Text = React.createClass({
  //一、以下实例化时期
  getDefaultProps() {
    console.log("1.getDefaultProps 获取默认属性");
    return { };
  },
  getInitialState() {
    console.log("2.getInitialState 获取初始状态");
    return { };
  },
  componentWillMount() {
    console.log("3.componentWillMount 此组件将要被渲染到目标组件内部");
  },
  componentDidMount() {
    console.log("5.componentWillMount 此组件已经被渲染到目标组件内部");
  },
  //二、以下存在时期
  componentWillReceiveProps() {
    console.log("6.componentWillReceiveProps 此组件将要收到属性");
  },
  shouldComponentUpdate(newProps, newState) {
    console.log("7.shouldComponentUpdate 组件是否应该被更新");
    return true;
  },
  componentWillUpdate() {
    console.log("8.componentWillUpdate 组件将要被更新");
  },
  componentDidUpdate() {
    console.log("10.componentDidUpdate 组件已经更新完成");
  },
  //三、以下销毁时期
  componentWillUnmount() {
    console.log("11.componentWillUnmount 组件将要销毁");
  },
  render() {
    console.log("4和9.render 组件将要渲染");
    return (
      <div>
        <h3>{this.props.myNumber}</h3>
      </div>
    );
  }
})
ReactDOM.render(
   <div>
      <Button />
   </div>,
  document.getElementById('example')
);
</script>
</body>
</html>
2、React16.4.0版组件之ES6写法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React实例</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
class Button extends React.Component {
  //name="计算器";state = {number: 0};
  //上下写法,二选一
  constructor(props) {
    super(props);
    this.name="计算器";
    this.state = {number: 0};
  };
  setNewNumber(number,event) {
    this.setState({number: this.state.number + 1})
  };
  render() {
    return (
      <div>
        <button onClick = {this.setNewNumber.bind(this,this.state.number,event)}>点击{this.name}</button>
        <Text myNumber = {this.state.number}></Text>
      </div>
    );
  }
}
class Text extends React.Component {
  //一、以下实例化时期
  constructor(props) {
    super(props);
    console.log("2.constructor 获取初始状态");
  }
  componentWillMount() {
    console.log("3.componentWillMount 此组件将要被渲染到目标组件内部");
  }
  componentDidMount() {
    console.log("5.componentWillMount 此组件已经被渲染到目标组件内部");
  }
  //二、以下存在时期
  componentWillReceiveProps() {
    console.log("6.componentWillReceiveProps 此组件将要收到属性");
  }
  shouldComponentUpdate(newProps, newState) {
    console.log("7.shouldComponentUpdate 组件是否应该被更新");
    return true;
  }
  componentWillUpdate() {
    console.log("8.componentWillUpdate 组件将要被更新");
  }
  componentDidUpdate() {
    console.log("10.componentDidUpdate 组件已经更新完成");
  }
  //三、以下销毁时期
  componentWillUnmount() {
    console.log("11.componentWillUnmount 组件将要销毁");
  }
  render() {
    console.log("4和9.render 组件将要渲染");
    return (
      <div>
        <h3>{this.props.myNumber}</h3>
      </div>
    );
  }
}
ReactDOM.render(
   <div>
      <Button />
   </div>,
  document.getElementById('example')
);
</script>
</body>
</html>
来源 https://www.runoob.com/try/try.php?filename=try_react_life_cycle2
 
六、插槽
1、portal插槽
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React插槽实例</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
  <div id="container"></div>
  <div id="outer"></div>
</body>
<script type="text/babel">
const container = document.getElementById('container');
const outer = document.getElementById('outer');
class Modal extends React.Component {
  constructor(props) {
    super(props);
    this.div = document.createElement('div');
  }
  componentDidMount() {
    outer.appendChild(this.div);
  }
  componentWillUnmount() {
    outer.removeChild(this.div);
  }
  render() {
    return ReactDOM.createPortal(
      this.props.children,
      this.div
    );
  }
}
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {clicks: 0};
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState(state => ({
      clicks: state.clicks + 1
    }));
  }
  render() {
    return (
      <div onClick={this.handleClick}>
        <div>{this.state.clicks}</div>
        <div><button>Click</button></div>
        <Modal>
          <div>
            <button className="modal">Click</button>
          </div>
        </Modal>
      </div>
    );
  }
}
ReactDOM.render(<Parent/>, container);
</script>
2、React.Children插槽
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React插槽实例</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
  <div id="container"></div>
  <div id="outer"></div>
</body>
<script type="text/babel">
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {clicks: 0};
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick(event) {
    console.log(event)
    this.setState(state => ({
      clicks: state.clicks + 1
    }));
  }
  render() {
    var that = this;
    return (
      <div>
        <div>{this.state.clicks}</div>
        <div><button onClick={this.handleClick}>clicks</button></div>
        <ul>
          {
            React.Children.map(this.props.children,function(item,index){
              if(index !=1){
                return <li onClick={that.handleClick}>{item}</li>
              }else{
                return <li onClick={that.handleClick}>{item}---{index+1}</li>
              }
            })
          }
        </ul>
      </div>
    );
  }
}
ReactDOM.render(<Parent>
  <span style={{cursor:'pointer',userSelect: 'none'}}>插槽一</span>
  <span style={{cursor:'pointer',userSelect: 'none'}}>插槽二</span>
  <span style={{cursor:'pointer',userSelect: 'none'}}>插槽三</span>
</Parent>, document.getElementById('container'));
</script>
</html>

七、React.15.6.0源码外框
/**
 * React v15.6.0
 */
(function (allFn) {
  if (typeof exports === "object" && typeof module !== "undefined") {
    module.exports = allFn()
  } else if (typeof define === "function" && define.amd) {
    define([], allFn)
  } else {
    var tempGlobal;
    if (typeof window !== "undefined") {
      tempGlobal = window
    } else if (typeof global !== "undefined") {
      tempGlobal = global
    } else if (typeof self !== "undefined") {
      tempGlobal = self
    } else {
      tempGlobal = this
    }
    tempGlobal.React = allFn()
  }
})(function () {
  var define, module, exports;
  return (function outerFn(first, second, third) {
    function recursion(number) {
      if (!second[number]) {
        if (!first[number]) {
          var error = new Error("Cannot find module '" + number + "'");
          throw error.code = "MODULE_NOT_FOUND", error
        }
        var module = second[number] = {
          exports: {}
        };
        first[number][0].call(module.exports, function (key) {
          var value = first[number][1][key];
          return recursion(value ? value : key)
        }, module, module.exports, outerFn, first, second, third)
      }
      return second[number].exports//在react实例化的过程中,这行代码不但因获取依赖而多次执行,而且还因获取react实例而最后执行。
    }
    for (var number = 0; number < third.length; number++) recursion(third[number]);//fn(16)第1次执行,执行结果没有变量接收
    return recursion //执行到这,整个逻辑就快结束了。前两行可以合并为一行:return recursion(third[0]),同时下面的"(48)"应当删掉。 
  })({ 2: [function (_dereq_, module, exports) { var thisVar = _dereq_(138) }, { "25": 25, "30": 30 }], }, {}, [16])(16)// fn(16)第2次执行,因为n[num]为真,所以直接返回n[num].exports并被挂在g.React上 
});
 
八、ant-design-pro脚手架的构成
Pro的底座是umi,umi是一个(基于)webpack之上的(自动化)整合工具。
Pro的核心是umi,umi的核心是webpack。
1、web 技术
2、Umi-前端应用框架(可整个或部分复用的软件)
(1)Node.js 前端开发基础环境
(2)Webpack 前端必学必会的打包工具
(3)React Router 路由库,被dva内置
(4)proxy 反向代理工具
(5)dva 轻量级的应用框架(可整个或部分复用的软件)
(6)fabric 严格但是不严苛的 lint 规则集
(7)TypeScript 带类型的 JavaScript
3、Ant Design 前端组件库
4、ProComponents 模板组件
5、useModel 简易数据流
6、编译时和运行时
(1)编译时,环境是node环境,可以使用fs,path等功能;没有使用webpack,不能使用jsx,不能引入图片
(2)运行时,编译完成,开始在浏览器环境运行,不能使用fs、path,有跨域的问题;这个环境被webpack编译过,可以写jsx,导入图片
7、Umi的插件
(1)plugin-access,权限管理
(2)plugin-analytics,统计管理
(3)plugin-antd,整合 antd UI 组件
(4)plugin-initial-state,初始化数据管理
(5)plugin-layout,配置启用 ant-design-pro 的布局
(6)plugin-locale,国际化能力
(7)plugin-model,基于 hooks 的简易数据流
(8)plugin-request,基于 umi-request 和 umi-hooks 的请求方案
8、Umi其它
(1)配置:开发配置和(浏览器)运行配置
(2)路由:配置路由和约定式路由
(3)插件:id和key,每个插件都会对应一个id和一个key,id是路径的简写,key是进一步简化后用于配置的唯一值。

九、前端路由:url有变化,但不向后台发送请求,
1、它的作用是 
(1)记录当前页面的状态; 
(2)可以使用浏览器的前进后退功能; 
2、hash模式帮我们实现这两个功能,因为它能做到: 
(1)改变url且不让浏览器向服务器发出请求; 
(2)监测 url 的变化; 
(3)截获 url 地址,并解析出需要的信息来匹配路由规则。 
3、history 模式改变 url 的方式会导致浏览器向服务器发送请求。
4、react前端路由触发条件
(1)<Link to={item.url}>{item.location}</Link>2)browserHistory.push('/aaa')

暂时留存
四、React组件生命周期
1、ES5写法
ES5写法之实例化时期
(1)propTypes = {}; getDefaultProps(){return{}};
(2)getInitialState(){return{}};
(3)componentWillMount//执行setState会合并到初始化状态中;获取从属性生成的状态
-----执行到这里,生命状态会被重置为null
(4)render//执行setState会发起updateComponent导致-死循环5)componentDidMount//执行setState会导致更新;这是发起异步请求去API获取数据的绝佳时期
ES5写法之存在期
(1)componentWillReceiveProps//执行setState会合并到状态中;
-----执行到这里,生命状态会被重置为null
(2)shouldComponentUpdate//执行setState会发起updateComponent导致-死循环3)componentWillUpdate//执行setState会发起updateComponent导致-死循环4)render//执行setState会发起updateComponent导致-死循环5)componentDidUpdate//可以有条件地执行setState
ES5写法之销毁时期
(1)componentWillUnmount//等待页面卸载,改变state没意义。
2、ES6写法(旧,React v16.3-)
ES6写法之实例化时期
(1static propTypes = {}; static defaultProps = {}; 
(2)constructor
(3)componentWillMount//执行setState会合并到初始化状态中;获取从属性生成的状态
-----执行到这里,生命状态会被重置为null
(4)render//执行setState会发起updateComponent导致-死循环5)componentDidMount//执行setState会导致更新;这是发起异步请求去API获取数据的绝佳时期
ES6写法之存在期
(1)componentWillReceiveProps//执行setState会合并到状态中;----将有变动
-----执行到这里,生命状态会被重置为null
(2)shouldComponentUpdate//执行setState会发起updateComponent导致-死循环3)componentWillUpdate//执行setState会发起updateComponent导致-死循环4)render//执行setState会发起updateComponent导致-死循环5)componentDidUpdate//可以有条件地执行setState
ES6写法之销毁时期
(1)componentWillUnmount//等待页面卸载,改变state没意义。
3、ES6写法(新,React v16.4+)
ES6写法之实例化时期
(1static propTypes = {}; static defaultProps = {}; 
(2)constructor
(3static getDerivedStateFromProps//执行setState会合并到初始化状态中;获取从属性生成的状态
-----执行到这里,生命状态会被重置为null
(4)render//执行setState会发起updateComponent导致-死循环5)componentDidMount//执行setState会导致更新;这是发起异步请求去API获取数据的绝佳时期
ES6写法之存在期
(1static getDerivedStateFromProps//执行setState会合并到状态中;----已有变动
-----执行到这里,生命状态会被重置为null
(2)shouldComponentUpdate//执行setState会发起updateComponent导致-死循环
//此处没有componentWillUpdate3)render//执行setState会发起updateComponent导致-死循环
//下(4)为新增4)getSnapshotBeforeUpdate//执行setState会发起updateComponent导致-死循环5)componentDidUpdate//可以有条件地执行setState
销毁时期
(1)componentWillUnmount//等待页面卸载,改变state没意义。
另外====1)getDerivedStateFromProps//返回一个对象来更新state,如果返回 null 则不更新任何内容。
 
 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM