forwardRef组件
# 概述
React.forwardRef用于包裹函数组件,向其传递第二个参数ref。普通函数组件只接受一个参数props。
# 源码分析
forwardRef接受一个函数参数render,render可以是函数组件,返回一个ReactNode
其源码如下,返回一个对象
function forwardRef(render){
return {
$$typeof:Symbol.for("react.forward_ref"),// 标识是forwardRef类型
render,
}
}
1
2
3
4
5
6
2
3
4
5
6
在生成fiber时,其fiber.tag为ForwardRef(11)。
# beginWork阶段
若fiber.tag为ForwardRef时,则调用updateForwardRef方法,用于处理forwardRef类型的fiber子节点。
updateForwardRef方法
updateForwardRef方法要做的事就是拆解,将fiber.ref作为渲染函数render的第二个参数。
function updateForwardRef(current,workInProgress,Component,nextProps,renderLanes){
// 读取渲染函数
const render= Component.render;
// 读取 fiber.ref 它本质是就是一个ref对象 即{current:null}
const ref = workInProgress.ref;
// 过滤掉nextProps上的ref属性,作为render的第一个参数
let propsWithoutRef;
if ('ref' in nextProps) {
propsWithoutRef = {};
for (const key in nextProps) {
if (key !== 'ref') {
propsWithoutRef[key] = nextProps[key];
}
}
} else {
propsWithoutRef = nextProps;
}
// 其余函数组件的差不多
// 准备好读取context的上下文
prepareToReadContext(workInProgress, renderLanes);
const nextChildren = renderWithHooks(
current,
workInProgress,
render,
propsWithoutRef,
ref,// 注意这个参数
renderLanes,
);
// bailout策略,组件更新时,props无变化会触发
if (current !== null && !didReceiveUpdate) {
bailoutHooks(current, workInProgress, renderLanes);
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
// 遍历子树
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
// 返回子节点
return workInProgress.child;
}
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
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
renderWithHooks方法
renderWithHooks方法顾名思义就是执行渲染函数包括函数组件内部的hooks
其源码如下:
function renderWithHooks<Props, SecondArg>(
current,
workInProgress,
Component,
props,
secondArg,
nextRenderLanes,
) {
// 渲染优先级赋值给renderLanes,下同currentlyRenderingFiber,在某些hooks调用时会用到
renderLanes = nextRenderLanes;
// 正在构建的fiber复制给currentlyRenderingFiber,方便在hooks中调用
currentlyRenderingFiber = workInProgress;
// 将fiber上的memoizedState、updateQueue以及渲染优先级清理
workInProgress.memoizedState = null;
workInProgress.updateQueue = null;
workInProgress.lanes = NoLanes;
// 切换hooks 分发器
ReactSharedInternals.H =
current === null || current.memoizedState === null
? HooksDispatcherOnMount
: HooksDispatcherOnUpdate;
// 执行组件,即forwardRef中的render,secondArg就是ref
let children = Component(props, secondArg);
// 若是在渲染阶段又触发了state变化
if (didScheduleRenderPhaseUpdateDuringThisPass) {
children = renderWithHooksAgain(
workInProgress,
Component,
props,
secondArg,
);
}
// 主要就是清理工作
finishRenderingHooks(current, workInProgress, Component);
return children;
}
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
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
# 总结
React.forwardRef就是给函数包装了一层,多传了一个ref参数,其余和普通函数组件一样,通常情况下和useImperativeHandle hook一起使用,用于子组件向父组件提供方法或变量等。
编辑 (opens new window)
上次更新: 2026/04/03, 01:41:21