• 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 则不更新任何内容。
     
     
  • 相关阅读:
    lhgdialogv3.13 使用点滴
    CheckBoxList 取值 及选中相关用法
    repeater 及 gridview 中绑定短日期
    数据库中日期大小的判断
    父子不同窗口间刷新传值
    子级Repeater获取父级Repeater绑定项的值
    vs.net 2010 web 项目中使用 webservice
    web打印实现方案 Lodop6.034 使用方法总结
    用 showModalDialog 方法回传数据到父页中去
    vs.net2010中使用 Ajax Control Toolkit
  • 原文地址:https://www.cnblogs.com/gushixianqiancheng/p/13859768.html
Copyright © 2020-2023  润新知