笔记----深入浅出《React和Redux》第二章

一、prop和state

1、易于维护组件的设计要素

(1)高内聚:把逻辑紧密的相关内容放在一个组件中

(2)低耦合:不同组件之间的依赖关系尽量弱化

2、React组件的数据

     分两种(都会引发组件的重新渲染):

    prop:组件对外接口;(一般用在组件之间传参)

            state:组件内部状态;(一般用在组件内部初始化)

     

3、React的prop:组件的prop很像是HTML元素的属性,但是HTML元素的属性值都是字符串,而React组件的prop所支持的类型几乎包含人一JS中所支持的类型

   注意:

              <SampleButton id=” sample”  borderWidth={2}  onClick={onButtonClick}   style={{color: ” red”}}  />

    style值中的{{}} , 外层表示JSX语法,内层表示对象

   (1)赋值 

      引入主入口组件App(另一个组件是第一章的demo)

                  

                 

      向三个ControlPanel的子组件Counter进行赋值,使用了caption和initValue两个prop

       

  (2)读取prop值

                 

                 通过props 进行 读取值

      结果显示:

                     

   (3)propType进行prop接口规范 

                             

                  此时对prop值进行了约束,

                            对caption必须是string,并且isRequired表示caption为必填值

                            对initValue必须为number

                  如果不按约束标准进行,如

                             

                 则报错 

                            

     注意:

                    即使在上面 propTypes 检查出错的情况下,组件依旧能工作 。 也就是说 propTypes检查只是一个辅助开发的功能,并不会改变组件的行为。

       

4、React的state:帮助记录组件自身的数据变化

              注意:组件的state必须是JS对象,不能是其他数据类型

  (1)初始化值

            

    可以换一种更优雅的写法

            

           一样可以实现默认值为0的效果

  (2)读取和更新state

            

    

    如果不使用setState(),修改代码如下

       

       此时点击“+”,则会弹出警告

        

     注意:

      在不使用setState()情况下,当连续点击10次“+”,数值并没有发生改变

                

          然后再次点击“-”时,数值直接变成9

            

      可以看出在我们连续点击“+”,其实state值已经开始进行累加,但是没有渲染到页面上,当我们点击“-”时,使用setState(),将减去1之后的结果9显示在页面上

      总结:直接使用state修改值,只修改了内部状态,并没有引起重新渲染

 

5、prop和state的对比

      (1)prop定义外部接口,state记录内部状态

  (2)prop的赋值在组件外部,state的赋值在组件内部

    (3)组件不应该改变prop的值,而state的值允许被修改

    (

      组件不应该改变prop的值的原因:

             假设一个场景,父组件包含多个子组件,然后将一个JS对象作为prop值传给这几个子组件,而某个子组件修改了这个对象的内部值,

                        那么其他子组件在读取那个对象的值时都会受到影响,导致程序混乱

        

        书上没有实践案例,自己写个小demo测试一下(将之前代码都放demo1了,此次新创建demo2),如下:

          

          

          首先,将父组件引入主入口文件

                                        

           在Parent组件中,初始化content对象,并将它作为prop值,分别传入两个子组件

           

          

          

          ChildOne组件对prop值进行直接修改,ChildTwo组件中对prop值进行显示,观察prop值是否变化

          

          结果:

          

          先点击ChildOne,然后点进ChilTwo进行显示,发现prop值在子组件Children发生改变,丢失了最初的值

           

                    

          

               )    

 二、组件的生命周期(v16.6.0)

    截取react官网生命周期图

                                                         

       (1)装载过程(Mount):组件第一次在DOM树中渲染过程;

       (2)更新过程(Update):当组件被重新渲染过程;

       (3)卸载过程(Unmount):组件从DOM中删除的过程;

   

1、装载过程的对应函数:

(1)constructor:当创建组件类的实例时,会调用对应构造函数

       注意:无状态的React组件,不需要定义构造函数

     

   React组件定义构造函数的目的:

                (i)初始化state

                (ii)绑定成员函数的this环境

注意:

      在ES6语法下,类的每个成员函数在执行时的this并不是和类实例自动绑定的,而在构造函数中,this就是当前组件的实例

  所以,为了方便将来的调用,在构造函数中将这个实例的特定函数绑定this为当前实例。

 如:

   this .onClickincrementButton = this .onClickincrementButton.bind(this);

      

(2)render:React组件中最重要的函数,一个React组件可以不实现其他所有函数,但是一定要实现render函数

    (i)某些特殊组件不是用来渲染界面,就让render函数返回一个null或者false,等于告诉React,这个组件不需要渲染DOM元素

            (ii)render函数是一个纯函数,根据this.state和this.props决定返回结果,不能在里面进行this.setState改变状态

       

(3)componentWillMount和componentDidMount:

    (i)componentWillMount:这个函数在渲染前被调用,几乎不会被使用到,因为所有可以在这个 component­WillMount 中做的事情,都可以提前到 constructor 中间去做

            (ii)componentDidMount:这个函数被调用时,组件已经被装载到DOM树上了

注意:

                

             执行顺序,结果:

    

  

           可以看出componentWillMount紧贴着自己组件的render函数之前被调用,componentDidMount在三个组件的render函数都被调用之后,

          三个组件的componentDidMount才连着被一起调用。

         

 原因:

       是因为 render 函数本身并不往 DOM 树上渲染或者装载内容,它只是返回一个 JSX表示的对象,然后由 React库来根据返回对象决定如何渲染。而 React库肯定是要把所有组件返回的结果综合起来,才能知道该如何产生对应的 DOM修改。 所以,只有 React库调用三个 Counter组件的 render函数之后,才有可能完成装载,这时候才会依次调用各个组件的 componentDidMount 函数作为装载过程的收尾 。

                

     (iii)componentWillMount可以在服务器端或浏览器端被调用,componentDidMount只能在浏览器端被调用

             (iv)在 componentDidMount 被调用的时候,组件已经被装载到 DOM 树上了,可以配合其他的第三方UI库(如:jQuery),进行添加新的功能

2、更新过程的对应函数:

(1)componentWillReceiveProps(nextProps)

              (i)通过 this.setState方法触发的更新过程不会调用这个函数;

              (ii)只要是父组件的render函数被调用,在render函数里面被渲染的子组件就会经历更新过程,

                   不管父组件传给子组件的props有没有改变,都会触发子组件的componentWillReceiveProps函数

  根据如下例子证明:

    父组件

    

        当触发onClick事件时,引发一个匿名函数,通过forceUpdate进行重新绘制(每个React组件都可以通过forceUpdate函数强行进行重新绘制)

    子组件

    

    

    运行结果

     

     显示页面初始化的数据,当进行点击Click me to repaint!时

    

           

    此时可以看出:

                     执行次序是当父组件的render被调用后,引发了子组件中componentWillReceiveProps的调用,最后子组件中的render也被调用了;

       再次渲染子组件时,它们的props并没有变化,但是子组件中componentWillReceiveProps依然被调用了  (有需要在子组件对nextProps和this.props值进行比较)

    再验证一下this.setState能不能触发componentWillReceiveProps

                         

    此时可以看出:                                      

       当前组件调用this.setState函数,不会引发componentWillReceiveProps函数             

    

(2)shouldComponentUpdate(nextProps,nexState):除了render之外最重要的函数,通过返回的布尔值决定什么时候组件不需要渲染,

         (i)如果我们要定义 shouldComponentUpdate,那就根据这两个参数,外加 this.props和 this.state来判断是返回true,还是false,来避免重复渲染

   (ii)通过this.setState函数引发更新过程,并不是立刻更新组件的state值,在执行到函数shouldComponentUpdate的时候,this.state依然是this.setState函数执行之前的值 

    如:

     

     运行结果:

            

    可以看出,三个Counter组件的render函数没有被调用,因为这个刷新没有改变caption值或count,减少了不必要的渲染

(3)componentWillUpdate和componentDidUpdate

    (i) componentDidUpdate函数,不仅在浏览器端可以执行,服务器端也可以执行

    (ii)在配合其他第三方UI库时(如:jQuery),当React组件被更新时,原有内容会被重新绘制,这时候需要在componentDidUpdate函数再次调用jQuery代码

3、卸载过程的对应函数:

  (1)componentWillUnmount:当React组件要从DOM树上删除之前,此函数会被调用,适合做一些清除工作(如:防止内存泄漏)

三、组件向外传递数据         

                         

      

        

        通过onUpdate这个prop值为onCounterUpdate函数,作为“桥梁”,通过函数的参数进行“沟通”

其他参考:https://react.docschina.org

原文地址:https://www.cnblogs.com/qianbin/p/10148755.html