useReducer更新源码实现
packages/react-reconciler/src/ReactFiberHooks.js
js
let currentHook = null;
const HooksDispatcherOnUpdate = {
useReducer: updateReducer
}
function updateWorkInProgressHook() {
if (currentHook === null) {
const current = currentlyRenderingFiber.alternate;
currentHook = current.memoizedState;
} else {
currentHook = currentHook.next;
}
const newHook = {
memoizedState: currentHook.memoizedState,
queue: currentHook.queue,
next: null
}
if (workInProgressHook === null) {
currentlyRenderingFiber.memoizedState = workInProgressHook = newHook;
} else {
workInProgressHook = workInProgressHook.next = newHook;
}
return workInProgressHook;
}
function updateReducer(reducer) {
const hook = updateWorkInProgressHook();
const queue = hook.queue;
const current = currentHook;
const pendingQueue = queue.pending;
let newState = current.memoizedState;
if (pendingQueue !== null) {
queue.pending = null;
const firstUpdate = pendingQueue.next;
let update = firstUpdate;
do {
const action = update.action;
newState = reducer(newState, action);
update = update.next;
} while (update !== null && update !== firstUpdate)
}
hook.memoizedState = newState;
return [hook.memoizedState, queue.dispatch];
}
export function renderWithHooks(current, workInProgress, Component, props) {
currentlyRenderingFiber = workInProgress; // 设置当前正在渲染的fiber节点
if (current !== null && current.memoizedState !== null) {
ReactCurrentDispatcher.current = HooksDispatcherOnUpdate;
} else {
ReactCurrentDispatcher.current = HooksDispatcherOnMount;
}
const children = Component(props); // 通过组件和props渲染子节点
currentlyRenderingFiber = null;
workInProgressHook = null;
currentHook = null;
return children; // 返回子节点
}packages/react-reconciler/src/ReactFiberBeginWork.js
js
export function updateFunctionComponent(current, workInProgress, Component, nextProps) {
const nextChildren = renderWithHooks(current, workInProgress, Component, nextProps);
reconcileChildren(current, workInProgress, nextChildren);
return workInProgress.child;
}
export function beginWork(current, workInProgress) {
switch (workInProgress.tag) {
case FunctionComponent:
const Component = workInProgress.type;
const nextProps = workInProgress.pendingProps;
return updateFunctionComponent(current, workInProgress, Component, nextProps);
}
}packages/react-reconciler/src/ReactFiberCompleteWork.js
diff
import {
createTextInstance,
createInstance,
appendInitialChild,
finalizeInitialChildren,
+ prepareUpdate
} from 'react-dom-bindings/src/client/ReactDOMHostConfig';
import {
NoFlags,
+ Update
} from "./ReactFiberFlags";
import {
HostComponent, HostRoot, HostText,
+ FunctionComponent
} from "./ReactWorkTags";
function markUpdate(workInProgress) {
workInProgress.flags |= Update;
}
function updateHostComponent(current, workInProgress, type, newProps) {
const oldProps = current.memoizedProps;
const instance = workInProgress.stateNode;
const updatePayload = prepareUpdate(instance, type, oldProps, newProps);
workInProgress.updateQueue = updatePayload;
if (updatePayload) {
markUpdate(workInProgress);
}
}
export function completeWork(current, workInProgress) {
const newProps = workInProgress.pendingProps;
switch (workInProgress.tag) {
case HostRoot:
bubbleProperties(workInProgress);
break;
case HostComponent:
const { type } = workInProgress;
+ if (current !== null && workInProgress.stateNode !== null) {
+ updateHostComponent(current, workInProgress, type, newProps);
+ } else {
const instance = createInstance(type, newProps, workInProgress);
appendAllChildren(instance, workInProgress);
workInProgress.stateNode = instance;
finalizeInitialChildren(instance, type, newProps);
+ }
bubbleProperties(workInProgress);
break;
+ case FunctionComponent:
+ bubbleProperties(workInProgress);
+ break;
case HostText:
const newText = newProps;
workInProgress.stateNode = createTextInstance(newText);
bubbleProperties(workInProgress);
break;
}
}