| name | react-style |
| description | React 核心源码编码风格 Skill。蒸馏自 facebook/react 核心包(packages/react-dom、
packages/react-reconciler、packages/scheduler),以及 Dan Abramov、Sebastian Markbåge、
Andrew Clark 的 PR review 和设计文档。
触发词:「React 源码风格」「Fiber 架构」「reconciler 风格」「react core style」「React 内部实现」。
适用:React 核心贡献、自定义 reconciler、调度器集成、Fiber 树遍历、effects 系统开发。
|
React 核心 · 编码 DNA
"Conceptual integrity matters more than individual pieces." — Sebastian Markbåge
"Make it work for the 90%. Document the 10%. Ignore the 1%." — React team on API design
角色定义
此 Skill 激活后,你写出的代码应该让 React 核心 contributor 在 code review 时感觉
「这代码是从 react-reconciler 里长出来的」,而不是「这是一个不了解 Fiber 的人写的」。
这意味着:Fiber 思维优先、effects 显式分层、调度器感知、Flow/TypeScript 类型驱动。
命名 DNA
6 条直觉规则:
-
Fiber 节点相关变量用 fiber、current、workInProgress(不缩写)
function updateFunctionComponent(current, workInProgress, Component, nextProps) {
const nextChildren = renderWithHooks(current, workInProgress, Component, nextProps);
reconcileChildren(current, workInProgress, nextChildren);
return workInProgress.child;
}
function updateFnComp(cur, wip, comp, props) { ... }
-
effect 标志位用全大写常量 + 位运算,命名以 Flags 结尾
export const NoFlags = 0b000000000000000000000000000;
export const PerformedWork = 0b000000000000000000000000001;
export const Placement = 0b000000000000000000000000010;
export const Update = 0b000000000000000000000000100;
export const Deletion = 0b000000000000000000001000000;
export const ChildDeletion = 0b000000000000000000010000000;
const EFFECT_TYPE = { PLACEMENT: 'placement', UPDATE: 'update' };
-
phase 函数命名:begin / complete / commit 三段式
function beginWork(current, workInProgress, renderLanes) { ... }
function completeWork(current, workInProgress, renderLanes) { ... }
function commitMutationEffects(root, finishedWork, committedLanes) { ... }
function processNode(fiber) { ... }
function handleWork(fiber) { ... }
-
lanes(优先级)相关变量总是带 Lanes 或 Lane 后缀
const renderLanes: Lanes = NoLanes;
const updateLane: Lane = requestUpdateLane(fiber);
function mergeLanes(a: Lanes, b: Lanes): Lanes { return a | b; }
function isSubsetOfLanes(set: Lanes, subset: Lanes): boolean { return (set & subset) === subset; }
const priority = 0;
const urgency = requestPriority();
-
Hook 链表节点:hook、workInProgressHook、currentHook(不叫 node)
let workInProgressHook: Hook | null = null;
let currentHook: Hook | null = null;
function updateWorkInProgressHook(): Hook {
let nextCurrentHook: null | Hook;
if (currentHook === null) {
const current = currentlyRenderingFiber.alternate;
nextCurrentHook = current !== null ? current.memoizedState : null;
} else {
nextCurrentHook = currentHook.next;
}
}
-
is 前缀用于布尔判断函数,has 前缀用于存在性检查
function isRootDehydrated(root: FiberRoot): boolean { ... }
function hasContextChanged(): boolean { ... }
function isFiberMounted(fiber: Fiber): boolean { ... }
function checkRootDehydrated(root) { ... }
function contextChanged() { ... }
结构偏好
Fiber 工作循环的三阶段严格分离,不能跨界:
function performUnitOfWork(unitOfWork: Fiber): void {
const current = unitOfWork.alternate;
let next = beginWork(current, unitOfWork, renderLanes);
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
completeUnitOfWork(unitOfWork);
} else {
workInProgress = next;
}
}
function commitRoot(root: FiberRoot, finishedWork: Fiber, lanes: Lanes): void {
commitBeforeMutationEffects(root, finishedWork);
commitMutationEffects(root, finishedWork, lanes);
root.current = finishedWork;
commitLayoutEffects(finishedWork, root, lanes);
}
function beginWork(current, workInProgress) {
document.getElementById('app').style.display = 'none';
}
Effects 链表:收集在 render phase,执行在 commit phase
function markUpdate(workInProgress: Fiber): void {
workInProgress.flags |= Update;
}
function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) {
const flags = finishedWork.flags;
switch (finishedWork.tag) {
case FunctionComponent: {
if (flags & Update) {
commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork, finishedWork.return);
}
break;
}
}
}
模块组织:按 Fiber tag(组件类型)而非功能分文件
react-reconciler/src/
├── ReactFiber.js # Fiber 节点创建
├── ReactFiberBeginWork.js # render phase 向下(按 tag switch)
├── ReactFiberCompleteWork.js # render phase 向上(按 tag switch)
├── ReactFiberCommitWork.js # commit phase(三趟 pass)
├── ReactFiberHooks.js # Function Component Hooks
├── ReactFiberFlags.js # effect 标志位常量
├── ReactFiberLane.js # 优先级 lanes 系统
└── ReactFiberScheduler.js # 与 scheduler 包交互
与 Scheduler 的交互:永远通过回调,不直接调用 Scheduler 内部 API
function ensureRootIsScheduled(root: FiberRoot, currentTime: number): void {
const nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes);
const newCallbackPriority = getHighestPriorityLane(nextLanes);
let schedulerPriorityLevel: PriorityLevel;
switch (lanesToEventPriority(nextLanes)) {
case DiscreteEventPriority:
schedulerPriorityLevel = ImmediateSchedulerPriority;
break;
case ContinuousEventPriority:
schedulerPriorityLevel = UserBlockingSchedulerPriority;
break;
default:
schedulerPriorityLevel = NormalSchedulerPriority;
}
newCallbackNode = scheduleCallback(
schedulerPriorityLevel,
performConcurrentWorkOnRoot.bind(null, root),
);
}
import { taskQueue } from 'scheduler/src/SchedulerMinHeap';
taskQueue.push(myTask);
Flow/TypeScript 类型注释习惯:
opaque type Lane: number = number;
opaque type Lanes: number = number;
type Effect = {
tag: HookFlags,
create: () => (() => void) | void,
destroy: (() => void) | void,
deps: Array<mixed> | void | null,
next: Effect,
};
function createFiber(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
): Fiber { ... }
注释哲学
注释解释"为什么",不解释"是什么":
if (enableSchedulingProfiler) {
markStateUpdateScheduled(fiber, lane);
}
const mergedLanes = mergeLanes(laneA, laneB);
TODO/FIXME 格式规范:
反模式(绝不这样写)
-
在 render phase 产生副作用
function beginWork(current, workInProgress) {
fetch('/api/data').then(setGlobalCache);
analytics.track('component_rendered');
return null;
}
-
直接修改 current Fiber(render phase 只能写 workInProgress)
function updateState(current, workInProgress) {
current.memoizedState = newState;
}
workInProgress.memoizedState = newState;
-
root.current 在 commit 中途切换
function commitRoot(root, finishedWork) {
root.current = finishedWork;
commitMutationEffects(root, finishedWork);
}
-
lane 优先级硬编码数字
if (fiber.lanes & 1) { ... }
if (priority === 2) { ... }
if (includesSomeLane(fiber.lanes, SyncLane)) { ... }
if (lane === InputContinuousLane) { ... }
-
跨包直接 import 内部模块
import { workInProgress } from 'react-reconciler/src/ReactFiberWorkLoop';
-
用 any 类型逃逸(Flow 里的 mixed 也要谨慎)
function updateFiber(fiber: any) { ... }
function updateFiber(fiber: Fiber) { ... }
-
Hooks 在条件语句里调用(连内部实现也要保持 hook 链表顺序)
function renderWithHooks(current, workInProgress, Component) {
if (someCondition) {
useState(null);
}
}
-
__DEV__ 检查不完整
throw new Error('Something went wrong in ' + componentName);
if (__DEV__) {
throw new Error(`Something went wrong in "${getComponentNameFromFiber(fiber)}"`);
} else {
throw new Error('Something went wrong.');
}
校验测试
- 双缓冲检查:你有没有在 render phase 写
current.xxx = ...?只能写 workInProgress.xxx。
- 副作用分层:DOM 操作、ref 更新、
useEffect 调用,有没有放在 commit phase?render phase 必须是纯的。
- lanes 可读性:优先级相关的变量有没有用常量(
SyncLane、DefaultLane)而不是裸数字?
来源