虽然现在都是使用函数组件,但是类组件还是有函数组件无法替代的地方,比如一些独有的生命周期、很方便的存一些变量而不需要一大堆useRef
、实例的方法调用更方便。
以下源码浅析React版本为17.0.1。
类组件的Fiber节点的创建
类组件的Fiber节点由父级节点进入reconcileChildren
方法后通过createFiberFromTypeAndProps
方法创建,在这个方法中会通过prototype.isReactComponent
判断该节点是否为ClassComponent
。
export function createFiberFromTypeAndProps( type: any, // React$ElementType key: null | string, pendingProps: any, owner: null | Fiber, mode: TypeOfMode, lanes: Lanes,): Fiber { // 省略无关代码... let fiberTag = IndeterminateComponent; if (typeof type === 'function') { // 通过prototype.isReactComponent判断是不是类组件 if (shouldConstruct(type)) { // 标记为类组件 fiberTag = ClassComponent; } } // 省略无关代码... return fiber;}// 通过prototype.isReactComponent判断是不是类组件function shouldConstruct(Component: Function) { const prototype = Component.prototype; return !!(prototype && prototype.isReactComponent);}
由于类组件需要继承Component
,所有存在prototype.isReactComponent
,该节点被标记为类组件,后续会进入类组件的判断。
类组件实例的创建和更新
上一步标记了该Fiber节点为ClassComponent
,该节点进入beginWork
阶段时会通过判断进入updateClassComponent
方法。
// ...省略无关代码case ClassComponent: { // 类组件type是类的本身,不是类的实例 const Component = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; // 合并defaultProps const resolvedProps = workInProgress.elementType === Component ? unresolvedProps : resolveDefaultProps(Component, unresolvedProps); return updateClassComponent( current, workInProgress, Component, resolvedProps, renderLanes, );}// ...省略无关代码
无论类组件是首次挂载还是更新,都会进入updateClassComponent
。
function updateClassComponent( current: Fiber | null, workInProgress: Fiber, Component: any, nextProps: any, renderLanes: Lanes,) { // 省略无关代码... // 类实例 const instance = workInProgress.stateNode; let shouldUpdate; // mount if (instance === null) { // 省略无关代码... // 创建并初始化类实例 constructClassInstance(workInProgress, Component, nextProps); mountClassInstance(workInProgress, Component, nextProps, renderLanes); shouldUpdate = true; } else if (current === null) { // 中断后继续渲染... } else { // update shouldUpdate = updateClassInstance( current, workInProgress, Component, nextProps, renderLanes, ); } // 返回子Fiber节点 const nextUnitOfWork = finishClassComponent( current, workInProgress, Component, shouldUpdate, hasContext, renderLanes, ); return nextUnitOfWork;}
updateClassComponent
中会针对Mount和Update分开判断。
Mount时
Mount时会创建实例,赋值updater
(也就是setState
和forceUpdate
等),初始化updateQueue
。主要调用了constructClassInstance方法和
mountClassInstance`方法。
constructClassInstance
constructClassInstance
方法主要创建类实例并绑定到Fiber节点,赋值updater
。
function constructClassInstance( workInProgress: Fiber, ctor: any, props: any,): any { let isLegacyContextConsumer = false; let unmaskedContext = emptyContextObject; let context = emptyContextObject; // 省略context相关代码... // 创建实例 const instance = new ctor(props, context); // 将state赋值到fiber节点的memoizedState const state = (workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state : null); // 赋值updater adoptClassInstance(workInProgress, instance); // 省略无关代码... return instance;}function adoptClassInstance(workInProgress: Fiber, instance: any): void { // 赋值updater instance.updater = classComponentUpdater; workInProgress.stateNode = instance; // 通过instance._reactInternals属性可以访问fiber节点 setInstance(instance, workInProgress);}
mountClassInstance
mountClassInstance
方法会对类实例的props
、state
赋值,并初始化updateQueue
,同时执行getDerivedStateFromProps
生命周期获取新的state
,同时根据判断执行componentWillMount
生命周期。
后续state
的值会通过执行updateQueue
的中的update
来更新。
function mountClassInstance( workInProgress: Fiber, ctor: any, newProps: any, renderLanes: Lanes,): void { // 类实例 const instance = workInProgress.stateNode; // 赋值props,state instance.props = newProps; instance.state = workInProgress.memoizedState; instance.refs = emptyRefsObject; // 初始化UpdateQueue initializeUpdateQueue(workInProgress); const contextType = ctor.contextType; if (typeof contextType === 'object' && contextType !== null) { // 把context挂在实例的context上 instance.context = readContext(contextType); } // 执行updateQueue计算新的state processUpdateQueue(workInProgress, newProps, instance, renderLanes); instance.state = workInProgress.memoizedState; const getDerivedStateFromProps = ctor.getDerivedStateFromProps; // 执行getDerivedStateFromProps赋值给state if (typeof getDerivedStateFromProps === 'function') { applyDerivedStateFromProps( workInProgress, ctor, getDerivedStateFromProps, newProps, ); instance.state = workInProgress.memoizedState; } // 调用componentWillMount if ( typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function') ) { // 调用UNSAFE_componentWillMount callComponentWillMount(workInProgress, instance); // 执行updateQueue处理UNSAFE_componentWillMount里发起的update processUpdateQueue(workInProgress, newProps, instance, renderLanes); // 赋值新的state instance.state = workInProgress.memoizedState; } // 有componentDidMount的情况下flags增加Update if (typeof instance.componentDidMount === 'function') { workInProgress.flags |= Update; }}
Update时
Update时调用updateClassInstance
来处理更新。
updateClassInstance
function updateClassInstance( current: Fiber, workInProgress: Fiber, ctor: any, newProps: any, renderLanes: Lanes,): boolean { // 类实例 const instance = workInProgress.stateNode; // clone当前updateQueue到workInProgress cloneUpdateQueue(current, workInProgress); // 当fiber走完beginWork阶段,memoizedProps会被赋值为pendingProps const unresolvedOldProps = workInProgress.memoizedProps; const oldProps = workInProgress.type === workInProgress.elementType ? unresolvedOldProps : resolveDefaultProps(workInProgress.type, unresolvedOldProps); instance.props = oldProps; const unresolvedNewProps = workInProgress.pendingProps; // context const oldContext = instance.context; const contextType = ctor.contextType; let nextContext = emptyContextObject; if (typeof contextType === 'object' && contextType !== null) { nextContext = readContext(contextType); } // ... const getDerivedStateFromProps = ctor.getDerivedStateFromProps; // 是否使用了新的生命周期 const hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; // 调用UNSAFE_componentWillReceiveProps if ( !hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function') ) { if ( unresolvedOldProps !== unresolvedNewProps || oldContext !== nextContext ) { callComponentWillReceiveProps( workInProgress, instance, newProps, nextContext, ); } } // 执行updateQueue之前重置forceUpdate标识 resetHasForceUpdateBeforeProcessing(); const oldState = workInProgress.memoizedState; let newState = (instance.state = oldState); // 执行updateQueue获取新的state processUpdateQueue(workInProgress, newProps, instance, renderLanes); newState = workInProgress.memoizedState; // 没看懂这段 if ( unresolvedOldProps === unresolvedNewProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing() ) { if (typeof instance.componentDidUpdate === 'function') { if ( unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState ) { workInProgress.flags |= Update; } } if (typeof instance.getSnapshotBeforeUpdate === 'function') { if ( unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState ) { workInProgress.flags |= Snapshot; } } return false; } // 执行getDerivedStateFromProps if (typeof getDerivedStateFromProps === 'function') { applyDerivedStateFromProps( workInProgress, ctor, getDerivedStateFromProps, newProps, ); newState = workInProgress.memoizedState; } // 根据forceUpdate标识和shouldComponentUpdate执行结果判断是否需要更新 const shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate( workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext, ); // 需要更新 if (shouldUpdate) { // 调用UNSAFE_componentWillUpdate生命周期 if ( !hasNewLifecycles && (typeof instance.UNSAFE_componentWillUpdate === 'function' || typeof instance.componentWillUpdate === 'function') ) { if (typeof instance.componentWillUpdate === 'function') { instance.componentWillUpdate(newProps, newState, nextContext); } if (typeof instance.UNSAFE_componentWillUpdate === 'function') { instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); } } if (typeof instance.componentDidUpdate === 'function') { workInProgress.flags |= Update; } if (typeof instance.getSnapshotBeforeUpdate === 'function') { workInProgress.flags |= Snapshot; } } else { // 没看懂这段 if (typeof instance.componentDidUpdate === 'function') { if ( unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState ) { workInProgress.flags |= Update; } } if (typeof instance.getSnapshotBeforeUpdate === 'function') { if ( unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState ) { workInProgress.flags |= Snapshot; } } workInProgress.memoizedProps = newProps; workInProgress.memoizedState = newState; } // 更新实例的props,state,context instance.props = newProps; instance.state = newState; instance.context = nextContext; return shouldUpdate;}
finishClassComponent
Mount和Update后都需要执行finishClassComponent
方法,该方法会返回经过reconcileChildren
处理后的child
节点。
function finishClassComponent( current: Fiber | null, workInProgress: Fiber, Component: any, shouldUpdate: boolean, hasContext: boolean, renderLanes: Lanes,) { // 标记需要赋值ref markRef(current, workInProgress); const didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags; // 不需要更新 if (!shouldUpdate && !didCaptureError) { return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); } const instance = workInProgress.stateNode; let nextChildren; // 出错了并且getDerivedStateFromError没有声明 if ( didCaptureError && typeof Component.getDerivedStateFromError !== 'function' ) { // 不渲染children,后续交给componentDidCatch处理 nextChildren = null; } else { // 执行render获取children nextChildren = instance.render(); } if (current !== null && didCaptureError) { forceUnmountCurrentAndReconcile( current, workInProgress, nextChildren, renderLanes, ); } else { // 处理children reconcileChildren(current, workInProgress, nextChildren, renderLanes); } workInProgress.memoizedState = instance.state; return workInProgress.child;}
类组件的更新调度
类的更新存在于Fiber节点上的updateQueue
,上面存储了Update
的信息,类组件可以通过setState
创建Update
并添加到updateQueue
发起更新调度,在Update时执行updateClassInstance
方法时会调用processUpdateQueue
方法计算新的state
。
UpdateQueue和Update的结构
在类组件Mount时执行mountClassInstance
方法时,内部会调用initializeUpdateQueue
方法初始化updateQueue
。
export function initializeUpdateQueue<State>(fiber: Fiber): void { const queue: UpdateQueue<State> = { baseState: fiber.memoizedState, // update基于baseState计算新的state firstBaseUpdate: null, // 优先级相关,被跳过的update lastBaseUpdate: null, // 优先级相关,被跳过的update shared: { pending: null, // 当前更新的update链表 }, effects: null, // update的callback,对应setState第二个参数 }; fiber.updateQueue = queue; // 初始化}
通过执行setState
会调用createUpdate
方法创建update
,并添加到updateQueue
中,Update
是一个环形链表,next
字段指向下一个Update
。
export function createUpdate(eventTime: number, lane: Lane): Update<*> { const update: Update<*> = { eventTime, lane, // 优先级相关 tag: UpdateState, // 根据tag判断更新state值 payload: null, // 对应setState的第一个参数 callback: null, // 对应setState的第二个参数 next: null, // 由于是链表结构,指向下一个update }; return update;}
processUpdateQueue
在类组件Update时会调用processUpdateQueue
方法中会执行updateQueue
来获得新的state
。
// 执行updateQueueexport function processUpdateQueue<State>( workInProgress: Fiber, props: any, instance: any, renderLanes: Lanes,): void { // ClassComponent中总是不为null const queue: UpdateQueue<State> = (workInProgress.updateQueue: any); // 全局标识判断是不是通过forceUpdate发起的更新 hasForceUpdate = false; // 由于优先级在上次更新被跳过的update链表 let firstBaseUpdate = queue.firstBaseUpdate; let lastBaseUpdate = queue.lastBaseUpdate; // 如果本次更新有pending updates,就拼接到baseUpdate let pendingQueue = queue.shared.pending; if (pendingQueue !== null) { queue.shared.pending = null; // 断开最后一个和第一个的连接,这样pendingQueue就不是环状了 const lastPendingUpdate = pendingQueue; const firstPendingUpdate = lastPendingUpdate.next; lastPendingUpdate.next = null; // 把pending updates连接到base queue if (lastBaseUpdate === null) { firstBaseUpdate = firstPendingUpdate; } else { lastBaseUpdate.next = firstPendingUpdate; } lastBaseUpdate = lastPendingUpdate; // 保证current和workInProgress一致 const current = workInProgress.alternate; if (current !== null) { // 省略代码... } } if (firstBaseUpdate !== null) { let newState = queue.baseState; let newLanes = NoLanes; let newBaseState = null; let newFirstBaseUpdate = null; let newLastBaseUpdate = null; let update = firstBaseUpdate; do { const updateLane = update.lane; const updateEventTime = update.eventTime; // 优先级不够的任务 if (!isSubsetOfLanes(renderLanes, updateLane)) { // clone跳过的Update const clone: Update<State> = { eventTime: updateEventTime, lane: updateLane, tag: update.tag, payload: update.payload, callback: update.callback, next: null, }; // 连接到firstBaseUpdate或lastBaseUpdate if (newLastBaseUpdate === null) { newFirstBaseUpdate = newLastBaseUpdate = clone; // 有跳过的Update下次以此时的state值计算 newBaseState = newState; } else { newLastBaseUpdate = newLastBaseUpdate.next = clone; } newLanes = mergeLanes(newLanes, updateLane); } else { // 优先级够不会被跳过的Update // 如果之前有被跳过的update,为了保证下次更新的连续性,也需要添加进laseBaseUpdate if (newLastBaseUpdate !== null) { const clone: Update<State> = { eventTime: updateEventTime, // NoLane在下次执行时不会被上面优先级不够跳过 lane: NoLane, tag: update.tag, payload: update.payload, callback: update.callback, next: null, }; newLastBaseUpdate = newLastBaseUpdate.next = clone; } // 根据update计算新的state newState = getStateFromUpdate( workInProgress, queue, update, newState, props, instance, ); const callback = update.callback; // 回调函数push进effects数组 if (callback !== null) { workInProgress.flags |= Callback; const effects = queue.effects; if (effects === null) { queue.effects = [update]; } else { effects.push(update); } } } // 下一个update update = update.next; if (update === null) { pendingQueue = queue.shared.pending; if (pendingQueue === null) { break; } else { // setState函数里又调用了setState会进入这个判断 const lastPendingUpdate = pendingQueue; const firstPendingUpdate = ((lastPendingUpdate.next: any): Update<State>); lastPendingUpdate.next = null; update = firstPendingUpdate; queue.lastBaseUpdate = lastPendingUpdate; queue.shared.pending = null; } } } while (true); if (newLastBaseUpdate === null) { newBaseState = newState; } queue.baseState = ((newBaseState: any): State); queue.firstBaseUpdate = newFirstBaseUpdate; queue.lastBaseUpdate = newLastBaseUpdate; markSkippedUpdateLanes(newLanes); workInProgress.lanes = newLanes; workInProgress.memoizedState = newState; // 反应到页面的state值 }}
processUpdateQueue
方法里会执行updateQueue
计算新的state
值,主要是其中包含了优先级以及跳过的Update
的判断有一些障目。主要逻辑还是循环Update
链表来获得新的state
。
state
值会通过getStateFromUpdate
方法来获得。
getStateFromUpdate
getStateFromUpdate
函数内会根据Update
类型来处理state
,这里主要关注由setState
发起的UpdateState
类型。
function getStateFromUpdate<State>( workInProgress: Fiber, queue: UpdateQueue<State>, update: Update<State>, prevState: State, nextProps: any, instance: any,): any { switch (update.tag) { // 省略代码... // tag为UpdateState case UpdateState: { const payload = update.payload; let partialState; if (typeof payload === 'function') { // 当第一个参数是函数时 partialState = payload.call(instance, prevState, nextProps); } else { // 第一个参数是对象 partialState = payload; } if (partialState === null || partialState === undefined) { return prevState; } // 合并state return Object.assign({}, prevState, partialState); }, // tag为ForceUpdate case ForceUpdate: { hasForceUpdate = true; return prevState; } } return prevState;}
setState和forceUpdate
setState
方法和forceUpdate
方法是继承Component
后原型链上的方法,本质是调用的在Mount时赋值当this.updater
。
Component.prototype.setState = function(partialState, callback) { this.updater.enqueueSetState(this, partialState, callback, 'setState');};Component.prototype.forceUpdate = function(callback) { this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');};
而this.updater
是在Mount时在constructClassInstance
方法里调用adoptClassInstance
方法时赋值的。
// adoptClassInstance...instance.updater = classComponentUpdater;// 通过instance._reactInternals属性可以访问fiber节点setInstance(instance, workInProgress);
classComponentUpdater
updater
本质调用的就是classComponentUpdater
的方法。
const classComponentUpdater = { enqueueSetState(inst, payload, callback) { // 从实例的_reactInternals属性取出fiber节点 const fiber = getInstance(inst); const eventTime = requestEventTime(); const lane = requestUpdateLane(fiber); // 创建update const update = createUpdate(eventTime, lane); update.payload = payload; if (callback !== undefined && callback !== null) { update.callback = callback; } // Update入队 enqueueUpdate(fiber, update); // 发起更新调度 scheduleUpdateOnFiber(fiber, lane, eventTime); }, enqueueForceUpdate(inst, callback) { const fiber = getInstance(inst); const eventTime = requestEventTime(); const lane = requestUpdateLane(fiber); const update = createUpdate(eventTime, lane); update.tag = ForceUpdate; if (callback !== undefined && callback !== null) { update.callback = callback; } enqueueUpdate(fiber, update); scheduleUpdateOnFiber(fiber, lane, eventTime); },};
setState
和forceUpdate
主要区别是Update
的tag
类型不同,在执行updateQueue
通过Update
获取state
时,getStateFromUpdate
方法返回不同的结果。
它们的回调函数会在后续的commit阶段执行。
类组件生命周期的执行
以下生命周期不包含未来不推荐使用的UNSAFE
生命周期,省略了部分无关代码。
render阶段
在未来开启concurrent
模式后,目前UNSAFE
的生命周期可能会因为渲染中断或优先级的高低执行多次,虽然目前不会有任何问题,但还是应该尽量避免使用。
constructor
constructor
在执行的时候实际上会传入context
作为第二个参数,这个在文档上是没有的。
function constructClassInstance(// ...): any { // 创建实例 const instance = new ctor(props, context);}
shouldComponentUpdate
shouldComponentUpdate
在Update时通过updateClassInstance
方法里每次都会调用。
function updateClassInstance(// ...): boolean { const shouldUpdate = checkHasForceUpdateAfterProcessing() || // 调用shouldComponentUpdate checkShouldComponentUpdate( workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext, );}
getDerivedStateFromProps
getDerivedStateFromProps
就像文档写的会在每次渲染前触发此方法,它在Mount时和Update时都会调用,通过执行函数获取一个新的state
值,并且会合并到当前state
上,同时会维护某些情况下updateQueue
的baseState
值。
// ...const getDerivedStateFromProps = ctor.getDerivedStateFromProps;if (typeof getDerivedStateFromProps === 'function') { applyDerivedStateFromProps( workInProgress, ctor, getDerivedStateFromProps, newProps, ); // 赋值给 instance.state = workInProgress.memoizedState;}
componentDidMount
虽然在render阶段不会执行componentDidMount
,但是它会在render
阶段打上flags
,后续commit
阶段才会执行。
function mountClassInstance(// ...): void { // 有componentDidMount的情况下flags增加Update if (typeof instance.componentDidMount === 'function') { workInProgress.flags |= Update; }}
componentDidMount和getSnapshotBeforeUpdate
和componentDidMount
相同,在render
阶段需要打上flags
,但是会判断props
和state
有没有变化。
function updateClassInstance(// ...): boolean { if (typeof instance.componentDidUpdate === 'function') { if ( unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState ) { workInProgress.flags |= Update; } } if (typeof instance.getSnapshotBeforeUpdate === 'function') { if ( unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState ) { workInProgress.flags |= Snapshot; } }}
commit阶段
commit阶段又分为3个阶段
- BeforeMutation阶段
- Mutation阶段
- Layout阶段
BeforeMutation阶段
BeforeMutation阶段在操作DOM前。
getSnapshotBeforeUpdate
通过current
判断是否为Update时,并执行getSnapshotBeforeUpdate
方法,按照文档的描述,这个生命周期可以做滚动条的位置,因为这时候获取DOM的值还是旧的。
function commitBeforeMutationLifeCycles( current: Fiber | null, finishedWork: Fiber,): void { switch (finishedWork.tag) { // ... case ClassComponent: { // 判断flags有Snapshot,在render阶段会打上flags if (finishedWork.flags & Snapshot) { // 通过current判断当前为Mount还是Update if (current !== null) { const prevProps = current.memoizedProps; const prevState = current.memoizedState; const instance = finishedWork.stateNode; const snapshot = instance.getSnapshotBeforeUpdate( finishedWork.elementType === finishedWork.type ? prevProps : resolveDefaultProps(finishedWork.type, prevProps), prevState, ); // 返回值是存在一个内部变量里的 instance.__reactInternalSnapshotBeforeUpdate = snapshot; } } return; } // ... }}
Mutation阶段
Mution阶段正在对DOM进行操作。
componentWillUnMount
当Fiber节点flags
包含Deletion
时,最后会进入commitUnmount
方法,由safelyCallComponentWillUnmount
方法调用componentWillUnMount
。
function commitUnmount( finishedRoot: FiberRoot, current: Fiber, renderPriorityLevel: ReactPriorityLevel,): void { switch (current.tag) { // ... case ClassComponent: { safelyDetachRef(current); const instance = current.stateNode; if (typeof instance.componentWillUnmount === 'function') { safelyCallComponentWillUnmount(current, instance); } return; } // ... }}
Layout阶段
Layou阶段是操作DOM后。
componentDidMount和componentDidMount
componentDidMount
和componentDidMount
在同一个函数中执行,通过current === null
判断是Mount还是Update来确定执行哪一个函数。
function commitLifeCycles( finishedRoot: FiberRoot, current: Fiber | null, finishedWork: Fiber, committedLanes: Lanes,): void { switch (finishedWork.tag) { case ClassComponent: { const instance = finishedWork.stateNode; if (finishedWork.flags & Update) { // mount时 if (current === null) { // 执行componentDidMount instance.componentDidMount(); } else { // update时,从current Fiber节点取出之前的props和state const prevProps = finishedWork.elementType === finishedWork.type ? current.memoizedProps : resolveDefaultProps(finishedWork.type, current.memoizedProps); const prevState = current.memoizedState; instance.componentDidUpdate( prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate, ); } } // 这里会执行updateQueue上的effects,其中存的是setState和forceUpdate的callback const updateQueue: UpdateQueue< *, > | null = (finishedWork.updateQueue: any); if (updateQueue !== null) { commitUpdateQueue(finishedWork, updateQueue, instance); } return; } }}
总结
以上简单从源码简单分析了类组件Fiber节点创建、类组件实例创建、更新,发起更新调度,生命周期的执行,回头再对比Hooks,我觉得某些情况类组件真的还挺方便,虽然大部分功能函数组件都能实现,但是还是的花一些时间使用Hooks来实现对应功能。