react学习 第六天 --- 组件化开发(二)

目录:

1 React性能优化SCU(重要)

2 获取DOM方式refs

3 受控和非受控组件(重要)

4 React的高阶组件(看你用不用得到)

5 portals和fragment

6 StrictMode严格模式

一、React性能优化SCU(重要)

 

上图说的是diff算法的更新的方式是跨城比较,算法复杂度是O(n^2),而react对算法优化后变成了不跨层的比较,复杂度O(n)。

 key是用于diff算法对dom的复用的

从服务器获取给key的值最好是id

 这里要注意:就算setState改变的变量和原来的值一样,render函数一样会被执行,子组件的render也会被执行,这是没有意义的重新渲染,但我们在子组件写入shouldComponentUpdate(){return false}那子组件就永远更新不了,也没有意义。所以需要掌握shouldComponentUpdate方法的参数判断方法还进行优化更新的性能

这里注意参数的位置是固定的,不能只写一个newState就觉得可以使用想要的newState了shouldComponentUpdate(newState),这样子其实只能取到nextProps的值。

 

如果是多个变量更新:

 这个SCU优化有个显而易见的缺点,那就是如果父组件改变的变量传递给子组件,子组件就要判断nextProps的改变,从而来允许render的重新渲染,而且变量多起来的时候,判断的条件也会变的庞大起来导致父组件子组件都需要使用SUC来进行性能优化,那么react用起来就会变得很麻烦解决办法就是使用下面图的PureComponent组件

 得是类组件才能使用PureComponent,因为需要继承,函数组件是用不了的。

使用方法就是将继承的Component换成PureComponent,并且将import引入的Component改成PureComponent继承后就不用写复杂的SCU判断就可以做到只有发生有意义的变量改变才会出现渲染,子组件也需要继承这个组件才能做到父组件传递的变量发生改变时才发生重新渲染。

 PureComponent同样也有缺点,就是它只做到浅层的比较,即比较第一层的对象是否相同,深层次是不进行比较的。就是说它只比较了state里面变量是否发生替换(比如下图中的books和friend,message),没有比较对象类型和数组类型的里面的值的变化。(如下图的books对象里的name,price等改变时不会被发现改变。)

PureComponent这么做相当于这样子做

 问题:为什么在下图的更新state的值再使用setState的方式可以发现变量改变从而进行render的重新渲染,而在PureComponent里面去无法更新了?

原因是下图在PureComponent的this.state.books和setState里面的this.state.books是指向一样的同一个books,只是里面的内容发生改变(本身只是浅比较),并没有替换,所以不改变。this.state.books.push改变对象的值,但是没有改变对象引用地址所以没办法触发PureComponent的重新渲染。我们使用的setState一般都是通过替换stae对象的方法改变的(对象引用地址不同),所以state肯定是改变了的。

由于函数组件不能继承PureComponent,所以想要使用PureComponent类似功能就得使用下图的高阶函数memo,使用方法如下图:

不可变的力量:

就是说state里面的值不要去直接修改,必须通过setState的方法改变state的值,而这么做的目的就是为了你能在继承了PureComponent的组件中能够更新,下图的方法即使改变了state的值,但是由于是直接修改了state的值,在PureComponent的组件中不能触发render的重新渲染,原因就是上面提到的引用地址没有发生变化。这时候应该写成下图这样子才能做到不直接修改state的变量而在PureComponent的组件中触发render的重新渲染,这里展示的是在数组里面添加数据。发生了替换。

 

 

二、获取DOM方式refs

ref获取DOM方式一:(不推荐)

ref获取DOM方式二:(推荐)

ref获取DOM方式三:(了解)

 当组件被挂载时立即调用:

保存到constructor里面以便在js代码中使用:

ref获取类组件实例:(只要能获取组件实例,就可以调用组件里面的实例方法、函数;函数式组件没有实例,不能使用下图方法来实现)

 

 需要绑定函数式组件的时候一般都是为了绑定某个元素DOM,函数式组件没有实例,所以绑定不了实例对象。方法是使用高阶函数forwardRef,这里就是后面高阶函数里面的知识,ref转发,通过高阶函数把ref抽取出来,绑定到元素上。

三、受控和非受控组件

加了value,check的input组件都是受控组件,受react管理。所以想使用非受控组件就不能加value和check属性得使用defaultValue和defaultCheck来设置默认值。

为了实现双向绑定的话,react使用的方法就是受控组件。受控组件就是input标签设置value的值为this.state里面的某个变量时,用户不能通过键盘改变其值的时候就叫做受控组件。

需要实现双向绑定:input必须要有value属性和onChange事件,通过onChange事件对this.state里面的变量修改,从而改变input的value属性的值

 通过计算属性来动态修改需要修改的变量名(就不用写那么多个方法来实现onChange事件): 

checkbox如何使用受控组件来实现单选同意协议按钮:

id和htmlFor一样是才能实现按字的时候也能让方框打钩,通过event.target.check来获取 是否

 checkbox如何使用受控组件来实现多选按钮:

实现onChange方法 

 

提交时获取已选中的爱好hobbies

select如何变成受控组件(单选的情况下):与普通表单获取是一样的

 select如何变成受控组件(多选的情况下):

 event.target.selectedOptions获取的值是类数组,不能使用数组方法,需要使用array.from循环获取可迭代对象成为数组。select多选需要按住shift的时候点击鼠标左键才能多选。

非受控组件实现监听和获取值,通过ref来操作dom:(不建议使用)

 

 

 

 

四、React的高阶组件(被hooks取代)

高阶函数:1、就是参数里面有另外一个函数:

2、函数的输出是另外一个函数:

 高阶组件:

 高阶组件类似于拦截,然后给传进来的组件进行额外的操作后再return出去。

用于给每个组件添加某个变量的高阶函数(增强): 

改变前的函数组件:改变后的函数组件:

如果是类组件需要使用高阶函数,则只需这样子做:

 还有要注意的是,如果父组件本来就有给子组件传递参数,那在高阶函数里面需要额外添加东西:

 

应用一、开发中,最常在context上下文的时候用到高阶函数来减少代码量(还是增强作用):

需要使用context给的变量的类组件只需要在export输出的时候使用高阶函数,在render渲染函数里面调用需要的变量就可以了

代码结构包括context文件,app.jsx,高阶函数with_theme.js,类组件product.jsx

context文件:

 

app.jsx里面的内容: 

不使用高阶函数的product写法:

高阶函数:

 需要使用context提供的变量的类组件product:(这里不影响app.jsx直接使用product组件)

 应用二、登录健全的作用,减少判断的代码:

cart.jsx需要判断用户是否登录的组件:

app.jsx根组件:(这里需要更新页面,直接使用setItem是没有更新页面效果的,可以使用this.steState改变某个变量值的方法来触发更新界面)

 高阶函数:

应用三、生命周期劫持,计算页面加载需要的时间:

高阶函数:

需要被测量时间的组件需要用高阶函数包裹:

 根组件app.jsx正常使用类组件就可以。

 

 

 

 

 

五、portals和fragment

portals和vue3里面的teleport是一样的;fragment和vue里面的template的作用一样,包裹的内容不会在浏览器里面显示出来template。

portals的作用就是在app.jsx根元素里面把某元素渲染到非root的根元素的其他元素上:

案例:

在类组件里面:

 在根组件里面:(这里用到了插槽)

 

fragment作用:本来需要用div来包裹的,在浏览器里面会显示成这样:

用了fragment之后:

 

 

六、StrictMode严格模式

全局开启严格模式:

局部开启严格模式:

开了严格模式之后,会默认在constructor、render、生命周期里执行两次代码

 

猜你喜欢

转载自blog.csdn.net/weixin_56663198/article/details/128727787