- 类组件生命周期函数包括:
- 初始化渲染阶段:
- constructor
- static getDerivedStateFromProps
- render
- componentDidMount
- 重新渲染阶段:
- static getDerivedStateFromProps
- shouldComponentUpdate
- render
- getSnapshotBeforeUpdate
- componentDidUpdate
- 卸载阶段:
- componentWillUnmount
- 初始化渲染阶段:
constructor
- 构造函数是在render阶段被调用,
beginWork中判断,如果是类组件则调用updateClassComponent
function updateClassComponent(
current: Fiber | null,
workInProgress: Fiber,
Component: any,
nextProps: any
) {
const instance = workInProgress.stateNode;
if (instance === null) {
// 如果instance空,说明没有类组件实例,则实例化
// Component是定义的类组件
constructorClassInstance(workInProgress, Component, nextProps);
}
}
function constructorClassInstance(workInProgress, ctor, props) {
// 实例化类组件,并关联上fiber
let instance = new ctor(props);
workInProgress.stateNode = instance;
}
static getDerivedStateFromProps
初次渲染和更新渲染,都会被调用,用于根据新的props生成新的state
function mountClassInstance(
workInProgress: Fiber,
ctor: any,
newProps: any
) {
const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
if (typeof getDerivedStateFromProps === 'function') {
const prevState = workInProgress.memoizedState;
let partialState = getDerivedStateFromProps(nextProps, prevState);
}
}
mountClassInstance在constructorClassInstance之后调用。
function updateClassComponent(
current: Fiber | null,
workInProgress: Fiber,
Component: any,
nextProps: any
) {
const instance = workInProgress.stateNode;
if (instance === null) {
// 初次渲染逻辑
} else {
// 更新渲染的逻辑,同样会调用getDerivedStateFromProps
updateClassInstance(current, workInProgress, Component, nextProps);
}
}
不管是初次渲染,还是更新渲染,getDerivedStateFromProps都是在render阶段执行的。
componentDidMount
function commitLayoutEffectOnFiber(
current: Fiber | null,
finishedWork: Fiber
) {
switch(finishedWork.tag) {
case ClassComponent: {
const instance = finishedWork.stateNode;
// 如果有update标记,就执行componentDidMount函数
if (finishedWork.flags | update) {
if (current === null) {
instance.componentDidMount();
}
}
}
}
}
commitLayoutEffectOnFiber是在commit阶段执行的,commit阶段分3步:
function commitRootImpl() {
// 1
commitBeforeMutationEffects();
// 2
commitMutationEffects();
// 3 commitLayoutEffectOnFiber就是在第3步中执行的
commitLayouteEffects();
}
那么update标识是什么时候设置的呢?
function mountClassInstance(
workInProgress: Fiber,
ctor: any
) {
const instance = workInProgress.stateNode;
if (typeof instance.componentDidMount === 'function') {
let fiberFlag = Update;
workInProgress.flag |= fiberFlag;
}
}
所以componentDidMount是在commit阶段执行的,且在重新渲染之后才执行。同时需要render阶段一起配合才行。
shouldComponentUpdate
function checkShouldComponentUpdate(
workInProgress,
ctor,
oldProps,
newProps,
oldState,
newState
) {
const instance = workInProgress.stateNode;
if (typeof instace.shouldComponentUpdate === 'function') {
// 如果自定义shouldComponentUpdate,则返回结果
let shouldUpdate = instance.shouldComponentUpdate(newProps, newState);
return shouldUpdate;
}
// 默认返回true
return true;
}
function updateClassInstance() {
// 得到新的state
if (typeof getDerivedStateFromProps === 'function') {
// 如果有的话,执行getDerivedStateFromProps
applyDerivedStateFromProps(workInProgress, ctor, newProps);
newState = workInProgress.memoizedState;
}
// 再判断是否更新
const shouldUpdate = checkShouldComponentUpdate(
workInProgress,
ctor,
oldProps,
newProps,
oldState,
newState
)
}
可见getDerivedStateFromProps和componentShouldUpdate都是在render阶段执行的,且有先后顺序:先计算新状态,后判断是否需要更新。
getSnapshotBeforeUpdate
function commitBeforeMutationEffectsOnFiber(finishedWork: Fiber) {
const flags = finishedWork.flags;
if ((flags & Snapshot) !== NoFlags) {
switch(finishedWork.tag) {
case ClassComponent: {
const current = finishedWork.alternate;
// current不为空说明才是更新,否则就是第一次渲染
if (current !== null) {
const prevProps = current.memoizedProps;
const prevState = current.memoizedState;
const instance = finishedWork.stateNode;
const snapshot = instance.getSnapshotBeforeUpdate(prevProps, prevState);
// 得到的返回值会传递给componentDidUpdate
instance.__reactInternalSnapshotBeforeUpdate = snapshot;
}
}
}
}
}
commitBeforeMutationEffectsOnFiber会在commit阶段的commitBeforeMutation中执行。
function updateClassInstance(
workInProgress: Fiber
) {
const instance = workInProgress.stateNode;
if (typeof instance.getSnapshotBeforeUpdate === 'function') {
// 如果有getSnapshotBeforeUpdate,那么设置标记
workInProgress.flags |= Snapshot;
}
}
componentDidUpdate
componentDidUpdate和componentDidMount被调用的地方是一样的。区别在于是否有current
function commitLayoutEffectOnFiber(
current: Fiber | null,
finishedWork: Fiber
) {
switch(finishedWork.tag) {
case ClassComponent: {
const instance = finishedWork.stateNode;
// 如果有update标记,就执行componentDidMount函数
if (finishedWork.flags | update) {
if (current === null) {
// 初次渲染
instance.componentDidMount();
} else {
// 更新渲染
instance.componentDidUpdate();
}
}
}
}
}
componentDidUpdate同样需要在render阶段置Update标记,位置在updateClassInstance中。
componentWillUnmount
function recursivelyTraverseDeletionEffects(
finishedRoot: FiberRoot,
nearestMountedAncestor: Fiber,
parent: Fiber
) {
let child = parent.child;
while(child !== null) {
// 处理当前子节点的componentWillUnmount函数
commitDeletionEffectsOnFiber(finishedRoot, nearestMountedAncestor, child);
// 处理当前子节点的兄弟节点
child = child.parent;
}
}
function commitDeletionEffectsOnFiber(
finishedRoot,
nearestMountedAncestor,
deletedFiber
) {
switch(deletedFiber.tag) {
case ClassComponent: {
const instance = deletedFiber.stateNode;
// 如果定义了componentWillUnmount,则执行
if (typeof instance.componentWillUnmount === 'function') {
instance.componentWillUnmount();
}
}
// 处理当前子节点的所有子节点
recursivelyTraverseDeletionEffects(
finishedRoot,
nearestMountedAncestor,
deletedFiber
);
}
}
componentWillUnmount是从父组件到组件的调用顺序
componentWillUnmount处于commit阶段的commitMutationEffects中执行且不用在render阶段设置标记(componentDidMount``componentDidUpdate``getSnapshotBeforeUpdate是需要的)