类组件生命周期
当发现fiber tag = 1时,表示遇到类组件。
/* workloop React 处理类组件的主要功能方法 */
function updateClassComponent(){
let shouldUpdate
const instance = workInProgress.stateNode // stateNode 是 fiber 指向 类组件实例的指针。
// instance 为组件实例,如果组件实例不存在,证明该类组件没有被挂载过,那么会走初始化流程
if (instance === null) {
// 1. workInProgress 树,当前正在调和的 fiber 树 2. Component 就是项目中的 class 组件3. nextProps 作为组件在一次更新中新的 props 。
constructClassInstance(workInProgress, Component, nextProps); // 组件实例将在这个方法中被new
// renderExpirationTime 作为下一次渲染的过期时间。
mountClassInstance(workInProgress,Component, nextProps,renderExpirationTime ); //初始化挂载组件流程。
// shouldUpdate 标识用来证明 组件是否需要更新。
shouldUpdate = true;
}else{
// 更新组件流程
shouldUpdate = updateClassInstance(current, workInProgress, Component, nextProps, renderExpirationTime)
}
if(shouldUpdate){
nextChildren = instance.render(); /* 执行render函数 ,得到子节点 */
// current 树,在初始化更新中,current = null ,在第一次 fiber 调和之后,会将 workInProgress 树赋值给 current 树。
reconcileChildren(current,workInProgress,nextChildren,renderExpirationTime) /* 继续调和子节点 */
}
}
React 的大部分生命周期的执行,都在 mountClassInstance 和updateClassInstance 这两个方法中执行。
初始化阶段
function mountClassInstance(workInProgress,ctor,newProps,renderExpirationTime) {
const instance = workInProgress.stateNode;
const getDerivedStateFromProps = ctor.getDerivedStateFromProps; /* ctor 就是我们写的类组件,获取类组件的静态方法 */
if (typeof getDerivedStateFromProps === 'function') {
const partialState = getDerivedStateFromProps(nextProps, prevState); // 得到将被合并的state
const memoizedState = partialState === null || partialState === undefined ? prevState : Object.assign({}, prevState, partialState); // 合并state
workInProgress.memoizedState = memoizedState;
instance.state = workInProgress.memoizedState; // 就是我们在组件中 this.state获取的state
}
// 当 getDerivedStateFromProps 和 getSnapshotBeforeUpdate 不存在的时候
if(typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && typeof instance.componentWillMount === 'function' ) {
instance.componentWillMount();
}
}
更新阶段
/**
* current: current 树,在初始化更新中,current = null ,在第一次 fiber 调和之后,会将 workInProgress 树赋值给 current 树。
* workInProgress: 当前正在调和的 fiber 树
* ctor: 就是我们写的类组件
**/
function updateClassInstance(current,workInProgress,ctor,newProps,renderExpirationTime) {
const instance = workInProgress.stateNode;
const hasNewLifecycles = typeof ctor.getDerivedStateFromProps === 'function'
if(!hasNewLifecycles && typeof instance.componentWillReceiveProps === 'function') {
if (oldProps !== newProps || oldContext !== nextContext) { // 浅比较 props 不相等
instance.componentWillReceiveProps(newProps, nextContext); // 执行生命周期
}
}
let newState = (instance.state = oldState);
if (typeof getDerivedStateFromProps === 'function') {
ctor.getDerivedStateFromProps(nextProps,prevState) /* 执行生命周期getDerivedStateFromProps ,逻辑和mounted类似 ,合并state */
newState = workInProgress.memoizedState;
}
let shouldUpdate = true
if(typeof instance.shouldComponentUpdate === 'function' ){
shouldUpdate = instance.shouldComponentUpdate(newProps,newState,nextContext);
}
if(shouldUpdate){
if (typeof instance.componentWillUpdate === 'function') {
instance.componentWillUpdate(); /* 执行生命周期 componentWillUpdate */
}
}
return shouldUpdate
}
- 初始化阶段:constructor -> getDerivedStateFromProps / componentWillMount -> render -> componentDidMount
- 更新阶段:componentWillReceiveProps( props 改变) / getDerivedStateFromProp -> shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentDidUpdate
- 卸载阶段:componentWillUnMount
- constructor:
- 在类组件创建实例时调用,而且初始化的时候执行一次,所以可以在 constructor 做一些初始化的工作。
- getDerivedStateFromProps:
- 代替 componentWillMount 和 componentWillReceiveProps
- 组件初始化或者更新时,将 props 映射到 state。
- 返回一个对象来更新 state,如果返回 null 则不更新任何内容。
getDerivedStateFromProps(nextProps,prevState)
getDerivedStateFromProps 方法作为类的静态属性方法执行,内部是访问不到 this。
- componentWillUpdate 后期版本作废,不要使用
- getSnapshotBeforeUpdate
- 配合componentDidUpdate 一起使用,计算形成一个 snapShot 传递给 componentDidUpdate 。保存一次更新前的信息。
getSnapshotBeforeUpdate(prevProps,preState) { return xxx}
函数组件生命周期
- useEffect
useEffect(()=>{
const subscription = props.source.subscribe();
return () => {
// 清除订阅
subscription.unsubscribe();
};
},dep)
useEffect(()=>{
return destory
},dep)
- useEffect 第一个参数 callback,返回的destory作为下一次callback执行之前调用,用于清除上一次 callback 产生的副作用。在执行下一个 effect 之前,上一个 effect 就已被清除。
- 第二个参数作为依赖项,是一个数组,可以有多个依赖项,依赖项改变,执行上一次callback 返回的 destory ,和执行新的 effect 第一个参数 callback 。
- 对于 useEffect 执行, 采用异步调用 ,对于每一个 effect 的 callback, 会被放入任务队列,等到主线程任务完成才执行。所以effect回调函数不会阻塞浏览器绘制视图。
- useLayoutEffect
- useLayoutEffect采用了同步执行, 是在DOM 绘制之前执行。
- useLayoutEffect callback 中代码执行会阻塞浏览器绘制。
Q: useEffect和 componentDidMount / componentDidUpdate 执行时机有什么区别 ?
A: useEffect是异步执行, 不会阻塞浏览器绘制。componentDidMount / componentDidUpdate 是同步执行的
如何使用useEffect替代componentDidMount?
A:
React.useEffect(()=>{
/* 请求数据 , 事件监听 , 操纵dom */
},[]) /* 切记 dep = [] */
ß