React链表结构的核心概念
1. Fiber

- 结构上,是一个对象
- 描述了一个React元素或Dom节点
- 新的协调引擎,主要目的是使Virtual DOM可以进行增量式渲染
export type Fiber = {
tag: WorkTag,
key: null | string,
elementType: any,
type: any,
stateNode: any,
return: Fiber | null,
child: Fiber | null,
sibling: Fiber | null,
index: number,
ref: null
| (((handle: mixed) => void) & {_stringRef: ?sting, ...}}
| RefObject,
pendingProps: any,
memoizedProps: any,
updateQueue: mixed,
memoizedState: any,
dependencies: Dependencies | null
mode: TypeOfMode,
flags: Flags,
subtreeFlags: Flags,
deletions: Array<Fiber> | null
lanes: Lanes,
childLanes: Lanes,
alternate: Fiber | null
}
- Fiber其实是一个vdom。
- Fiber数据结构里,tag为节点类型,child为子Fiber,sibling为下一个兄弟Fiber,render为父级Fiber,alternate为老节点的Fiber(上一个fiber);
- Fiber数据结构里,节点为原生元素(tag为5),stateNode为dom节点;节点为类组件(tag为1),stateNode为组件实例;节点为函数组件(tag为0),stateNode为null。
- Fiber数据结构里,flags属性,placement代表节点
新增、插入;update代表节点更新;deletion代表节点删除。
- Fiber数据结构里,type属性,值为字符串即原生标签、值为函数且type.prototype.isReactComponent即类组件、值为函数且!type.prototype.isReactComponent即函数组件、值为undefined即文本。
2. Hook
- 解决类组件难以解决的问题,比如状态复用、组件臃肿等
- 每次函数组件执行的时候,hook都会再次执行;Vue Composition只是首次执行一次
- 结构上,为单链表,hook顺序代表链表的唯一性,所以引用hook不能使用条件、循环等语句
export type Hook = {
memoizedState: any,
baseState: any,
baseQueue: Update<any, any> | null,
queue: any,
next: Hook | null
}
3. Update
- 初次渲染、setState、forceUpdate的更新
- 通过批量更新实现的异步更新
function enqueueUpdate<S, A>(
fiber: Fiber,
queue: UpdateQueue<S, A>,
update: Update<S, A>,
lane: Lane
) {
...
}
4. Effect
- useEffect和useLayoutEffect处理effect
函数组件初次渲染
- 记录effect和deps
- pushEffect函数,把effect单向循环链表,存储在fiber.updateQueue.lastEffect上
function mountEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null
):void {
return mountEffectImpl(
PassiveEffect | PassiveStaticEffect,
HookPassive,
create,
deps
)
}
function mountEffectImpl(fiberFlags, hookFlags, create, deps): void {
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
currentlyRenderingFiber.flags = fiberFlags;
hook.memoizedState = pushEffect(
HookHasEffect | hookFlags,
create,
undefined,
nextDeps
)
}
函数组件更新阶段
- 相对于初次渲染阶段,更新阶段的不同之处在于多了对deps的对比,如果组件更新前后,依赖项不变,则后续的effect并不会添加到updateQueue中,也就意味着create函数不会执行。
- 并且,初次渲染阶段不会记录destory函数,只需函数组件更新阶段记录到effect中。
- 在记录阶段,effect都是记录到fiber.updateQueue中
5. 总结
- 单向链表fiber、hook
- 单向循环链表update、effect