一些React源码的东西

一些React源码的东西

基础数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
interface ReactElement {
$$typeof: typeof Symbol.for('react.element');
type: string;
key: string|number;
ref: string|object;
props: object;
_owner: unknown;
}

type ReactNode =
| null
| boolean
| number
| string
| ReactElement
| ReactPortal
| Iterable<ReactNode>;

type ReactEmpty = null | void | boolean;

type ReactNodeList = ReactEmpty | ReactNode;

type RootType = {
render(children: ReactNodeList): void;
unmount(): void;
_internalRoot: FiberRoot;
};

const enum RootTag = {
LegacyRoot,
BlockingRoot,
ConcurrentRoot,
}

interface BaseFiberRootProperties {
tag: RootTag;
// The currently active root fiber. This is the mutable root of the tree.
current: Fiber;

// TODO
}

interface FiberRoot extends BaseFiberRootProperties {}

Fiber

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Fiber WorkTag
const enum WorkTag = {
FunctionComponent,
ClassComponent ,
IndeterminateComponent, // Before we know whether it is function or class
HostRoot , // Root of a host tree. Could be nested inside another node.
HostPortal, // A subtree. Could be an entry point to a different renderer.
HostComponent,
HostText,
Fragment,
Mode,
ContextConsumer,
ContextProvider,
ForwardRef,
Profiler,
SuspenseComponent ,
MemoComponent ,
SimpleMemoComponent ,
LazyComponent ,
IncompleteClassComponent,
DehydratedFragment ,
SuspenseListComponent ,
FundamentalComponent ,
ScopeComponent ,
OffscreenComponent ,
LegacyHiddenComponent ,
CacheComponent,
}

// A Fiber is work on a Component that needs to be done or was done. There can
// be more than one per component.
interface Fiber {
tag: WorkTag;
// 与本Fiber关联的状态
stateNode: any;
// 状态上下文
memoizedState: any;
// 状态更新队列和对应的callback
updateQueue: any;
// TODO
}

Lane

1
2
3
4
// react-reconciler/src/ReactFiberLane.new.js
type Lanes = number;
type Lane = number;
type LanePriority = number; // 0 ~ 17

UpdateQueue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// react-reconciler/src/ReactUpdateQueue.new.js

interface Update<State> {
eventTime: number;
lane: Lane;
tag: 0 | 1 | 2 | 3;
payload: any;
callback?: () => any;
next?: Update<State>;
}

interface SharedQueue<State> {
pending?: Update<State>;
}

interface UpdateQueue<State> {
baseState: State;
firstBaseUpdate?: Update<State>;
lastBaseUpdate?: Update<State>;
shared: SharedQueue<State>;
effects?: Update<State>[];
}

// TODO

一些流程

ReactElement

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function createElement(
type: unknown,
config: unknown,
children?: ReactElement[]
): ReactElement;

function cloneElement(
element: ReactElement,
config: unknown,
children?: ReactElement[]
): ReactElement;

function isValidElement(object: unknown) {
return (
typeof object === "object" &&
object !== null &&
object.$$typeof === Symbol.for("react.element")
);
}

ReactDOM.render()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function render(
element: ReactElement,
container: HTMLElement | HTMLDocument,
callback: Function
): unknown {
return legacyRenderSubtreeIntoContainer(element, container, callback);
}

function legacyRenderSubtreeIntoContainer(
element: ReactElement,
container: HTMLElement | HTMLDocument,
callback: Function
): unknown {
let root: RootType = container._reactRootContainer;
let fiberRoot;

if (!root) {
root = container._reactRootContainer = new ReactDOMBlockingRoot(
container,
RootTag.LegacyRoot
);
fiberRoot = root._internalRoot;

unbatchedUpdates(() => {
updateContainer(element, fiberRoot, null, callback);
});
} else {
fiberRoot = root._internalRoot;
updateContainer(element, fiberRoot, null, callback);
}

return fiberRoot.child.stateNode;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class ReactDOMBlockingRoot {
private _internalRoot;

constructor(container: HTMLElement | HTMLDocument, tag: RootTag) {
const fiberRoot = createFiberRoot(container, tag)
// mark container as root
container[`__reactContainer$${Math.random().toString(36).slice(2)}`] = fiberRoot.current;

// 在container节点上监听所有事件冒泡,进行事件代理
// listenToAllSupportedEvents

this._internalRoot = fiberRoot;
}

render(children: ReactNodeList) {
updateContainer(children, this._internalRoot, null, null);
}

unmount() {
updateContainer(null, this._internalRoot, null, () => {
unmarkContainerAsRoot(this._internalRoot.containerInfo)
})
}
}

function createFiberRoot(container: HTMLElement | HTMLDocument, tag: RootTag): FiberRoot {
// 创建一个FiberRoot对象,填充必要属性
const root: FiberRoot = new FiberRootNode(container, tag);
// 创建一个FiberNode对象,将其node tag设置为HostRoot
const uninitializedFiber = new FiberNode(WorTag.HostRoot);
// 将新建的FiberNode对象作为当前活动的Fiber
root.current = uninitializedFiber;
// 将FiberRoot作为FiberNode的状态对象
uninitializedFiber.stateNode = root;

// ... 这里有一些根据全局开关 __EXPERIMENTAL__ 初始化 root.pooledCache 的逻辑

// 初始化fiber node 状态
const initialState = {
element: null;
}
uninitializedFiber.memoizedState = initialState;

// 初始化Fiber node updateQueue
const queue: UpdateQueue = {
baseState: uninitializedFiber.memoizedState,
}

return root;
}

updateContainer()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const enum ExecutionContext = {
NoContext = 0b0000000,
EventContext = 0b0000010,
DiscreteEventContext = 0b0000100,
LegacyUnbatchedContext = 0b0001000,
RenderContext = 0b0010000,
CommitContext = 0b0100000,
RetryAfterError = 0b1000000,
}

let executionContext = ExecutionContext.NoContext;

function unbatchedUpdates<A, R>(fn: (a: A) => R, a: A): R {
const prevExecutionContext = executionContext;
}
作者

m3m0ry

发布于

2020-12-25

更新于

2020-12-25

许可协议

评论