useReducer更新源码实现
react-reconciler/src/ReactFiberCommitWork.js
js
import { appendChild, insertBefore, commitUpdate } from "react-dom-bindings/src/client/ReactDOMHostConfig";
import { Placement, MutationMask, Update } from "./ReactFiberFlags";
export function commitMutationEffectsOnFiber(finishedWork, root) {
const current = finishedWork.alternate;
const flags = finishedWork.flags;
switch (finishedWork.tag) {
case HostComponent:{
recursivelyTraverseMutationEffects(root, finishedWork);
commitReconciliationEffects(finishedWork);
if (flags & Update) {
const instance = finishedWork.stateNode;
if (instance !== null) {
const newProps = finishedWork.memoizedProps;
const oldProps = current !== null ? current.memoizedProps : newProps;
const type = finishedWork.type;
const updatePayload = finishedWork.updateQueue;
finishedWork.updateQueue = null;
if (updatePayload) {
commitUpdate(instance, updatePayload, type, oldProps, newProps, finishedWork);
}
}
}
break;
}
}
}packages/react-dom-bindings/src/client/ReactDOMHostConfig.js
js
import { setInitialProperties, diffProperties, updateProperties } from './ReactDOMComponent';
export function prepareUpdate(domElement, type, oldProps, newProps) {
return diffProperties(domElement, type, oldProps, newProps);
}
export function commitUpdate(domElement, updatePayload, type, oldProps, newProps) {
updateProperties(domElement, updatePayload, type, oldProps, newProps);
updateFiberProps(domElement, newProps);
}packages/react-dom-bindings/src/client/ReactDOMComponent.js
js
export function diffProperties(domElement, tag, lastProps, nextProps) {
let updatePayload = null;
let propKey;
let styleName;
let styleUpdates = null;
for (propKey in lastProps) {
if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey) || lastProps[propKey] === null) {
continue;
}
if (propKey === STYLE) {
const lastStyle = lastProps[propKey];
for (styleName in lastStyle) {
if (lastStyle.hasOwnProperty(styleName)) {
if (!styleUpdates) {
styleUpdates = {};
}
styleUpdates[styleName] = '';
}
}
} else {
(updatePayload = updatePayload || []).push(propKey, null);
}
}
for (propKey in nextProps) {
const nextProp = nextProps[propKey];
const lastProp = lastProps !== null ? lastProps[propKey] : undefined;
if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp || (nextProp === null && lastProp === null)) {
continue;
}
if (propKey === STYLE) {
if (lastProp) {
for (styleName in lastProp) {
if (lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName))) {
if (!styleUpdates)
styleUpdates = {};
styleUpdates[styleName] = '';
}
}
for (styleName in nextProp) {
if (nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName]) {
if (!styleUpdates)
styleUpdates = {};
styleUpdates[styleName] = nextProp[styleName];
}
}
} else {
styleUpdates = nextProp;
}
} else if (propKey === CHILDREN) {
if (typeof nextProp === 'string' || typeof nextProp === 'number') {
(updatePayload = updatePayload || []).push(propKey, nextProp);
}
} else {
(updatePayload = updatePayload || []).push(propKey, nextProp);
}
}
if (styleUpdates) {
(updatePayload = updatePayload || []).push(STYLE, styleUpdates);
}
return updatePayload;
}
export function updateProperties(domElement, updatePayload) {
updateDOMProperties(domElement, updatePayload);
}
function updateDOMProperties(domElement, updatePayload) {
for (let i = 0; i < updatePayload.length; i += 2) {
const propKey = updatePayload[i];
const propValue = updatePayload[i + 1];
if (propKey === STYLE) {
setValueForStyles(domElement, propValue);
} else if (propKey === CHILDREN) {
setTextContent(domElement, propValue);
} else {
setValueForProperty(domElement, propKey, propValue);
}
}
}