Jinuss's blog Jinuss's blog
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

Web、WebGIS技术博客
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 《React源码》笔记
  • React-reconciler
东流
2026-04-01
目录

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

在生成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
  • 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

# 总结

React.forwardRef就是给函数包装了一层,多传了一个ref参数,其余和普通函数组件一样,通常情况下和useImperativeHandle hook一起使用,用于子组件向父组件提供方法或变量等。

编辑 (opens new window)
上次更新: 2026/04/03, 01:41:21
最近更新
01
useId
04-03
02
useImperativeHandle
04-01
03
memo组件
04-01
更多文章>
Theme by Vdoing | Copyright © 2024-2026 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式