高阶组件
- 高阶组件就是一个函数,传给她一个组件,它返回一个新的组件。
- 高阶组件的作用其实就是为了组件之前的代码复用。
高阶组件的用处,属性代理, 方向继承
属性代理
像之前实现的redux的connext就是使用高阶组件的写法。
通过高阶组件传入了一个title属性,如果所有组件都需要这个属性,只需要使用这个高阶函数代理一下即可。
使用装饰器的写法会报错,因为它不支持。所以我们安装一个plugin.
然后在babel.config.js文件进行配置
在书写一个jsconfig.json文件
这样就可以i使用装饰器了,装饰器的功能是会将类传入装饰其中,然后去加强类的一些比如属性和方法。如果装饰器中返回一个值,那么会将该值作为最终的值。也就是我们渲染出来的vdom。
具体可以了解这篇装饰器
高阶函数第二个特点,反向继承
拦截生命周期,拦截state,渲染过程。
我们继续使用这个。然后使用高阶组件,反向继承,
方法就是让返回的类继承传入的类,接着就可以通过super进行一系列的操作,拦截生命周期,渲染状态等等
我们没调用Home的componnetWillMount,他就不会执行。
cloneElement方法的实现:
主要就是浅复制返回一个对象。
多个context的实现
react对context的实现是
而我们对context的实现是这样的,
所以我们重新改造一下。
让createContext返回一个对象,标识typeof,因为babel转化的时候会根据这个转化,最后在创建的时候针对处理这个vdom就行。
因为我们现在的vdom不止三种类型了,有原生dom,函数组件,类组件,provider组件,forwardref组件,consumer组件。
在compareTwoVdom的里面调用的updateElement方法也应该做出改变,因为现在的div下面可能有的是Provier组件,有的是Consumer组件,所以必须做出对应的判断
不管是什么类型的vdom,更改的时候都是要拿到对应的vdom去进行比对。而provider组建的vdom上的props的children就是指向里层的vdom。
这样就完成了对context的改造。
针对provier和consumer组件做标识,在创建的时候处理,将value赋值到返回的context对象中,然后在render之前再将Value传给context属性。
render props
- render props是一种在React组件之间使用的一个值为函数的prop共享代码的简单技术。
- 具有render prop的组件接受一个函数,该函数返回一个React元素并调用它,而不是实现自己的渲染逻辑。
- render prop是一个用于告知组件需要渲染什么内容的props
- 这也是逻辑复用的一种方式。
例子
这时候渲染的内容是不是固定的?我们无法改变,所以需要从外界传入进来。首先是
children
通过children传入
props
通过props传入。
- render-prop可以与HOC(高阶组件)互换
Home只注重渲染,Wrapper注重逻辑这就是转换成HOC的写法。
render-prop就是接受一个值为函数的props的属性,如porp.render,这个render返回一个react元素,用来作为渲染的内容,render-prop组件本身没有渲染内容,增加复用性。
Purcomponent的实现
继承Purcomponent的组件会默认调用shouldComponent方法对新老的Props和state进行比较,返回true即更新,返回false即不更新。
我们先看现在的实现
即使state中的number是一样的,但是还是会重新render
这样是不对的,所以我们要实现PureComponent的效果。
思路就是Purcomponent继承了Component并且重写了ShouldComponentUpdate方法。
实现方法很简单,重写shouldComponentUpdate方法即可,通过shallowEqual比对新老state,和新老Props。
主要是对传入的两个对象进行浅比较。
看效果:
输入0的时候,1+0还是1,所以state不
变。所以不会渲染。当
再将father组件换位Component试试
即使state不变,但是father组件依然会重新render。所以PurComponent组件就实现完毕了。
函数组件的实现方式 React.memo
源码的memo实现
也是标识类型$$typeof,由babel转化为这个对象。
第二个参数是一个比对函数,默认实现的是
(preProps, nextProps)=>shallowEqual(preProps, nextProps)
react内部有实现shallowEqual这个方法。
我们来实现memo这个方法。
首先看
再看memo方法的实现
这里需要注意一下,与Provier,Consumer,ForwardRef一样,memo返回的也是一个对象,当他作为一个元素渲染的时候,会被babel转化为类似这样
也就是说memo的组件会被转化为
React.createElement({$$typeof: REACT_MeMo,comapre, type, } ,{id: 123123})
即最终的rencet元素应该是这样的
Provider跟ConSumer也是同样的道理。
memo的实现并不难,难的是处理这个元素。
这里需要将老的props放到vdom上方便比较,这就是首次渲染的memo组件应该处理的事情。如图:
修改的时候,也要根据type值的不同做处理、
这样就完成了对Memo的处理,看效果:
memo组件就完成了。