React16源码: React中的FunctionComponent的源码实现

Function Component

1 )概述

  • FunctionComponent 会引出调和子节点的过程
  • 调和子节点是一个统一的过程,和各类组件不同类型没有太大关系
    • 在 ReactDOM.render 第一次时,只有一个Fiber对象
    • 这个Fiber对象它会保存它的props, 里面有很多的children
    • 里面的 props.children 是 App 对应的 ReactElement
    • 这个 ReactElement 不是 Fiber 对象,肯定要去创建它的Fiber对象
    • 在 ReactDom.render 的过程中, 是一步一步的往下执行
    • 对于children,肯定要判断 ReactElement 的类型
    • 基于不同类型做对应的处理方式,这个过程肯定是非常重要的

2 )源码

定位到 packages/react-reconciler/src/ReactFiberBeginWork.js

的 beginWork 函数,在 beginWork 下面的 执行 switch case 中

js 复制代码
// beginWork 函数中的截取部分
case FunctionComponent: {
  // 这里的 type 就是 ReactElement 里面存储的 type 属性
  // 这个 type 属性里面存储的就是 组件,如果是dom原生组件就是字符串
  // 如果组件是 function component 就是一个方法,如果是 class component 它就是类
  const Component = workInProgress.type;
  // pendingProps 是新渲染的时候产生的 props,这个和调和子节点有关系
  const unresolvedProps = workInProgress.pendingProps;
  // 这个 resolvedProps 是和 Suspense 组件有关的,throw 的是一个 Promise 可能会resolve出一些东西
  // 可以先默认 resolvedProps 就是上面的 unresolvedProps
  const resolvedProps =
    workInProgress.elementType === Component
      ? unresolvedProps
      : resolveDefaultProps(Component, unresolvedProps);
  return updateFunctionComponent(
    current,
    workInProgress,
    Component,
    resolvedProps,
    renderExpirationTime,
  );
}

进入到 updateFunctionComponent 方法

js 复制代码
function updateFunctionComponent(
  current,
  workInProgress,
  Component,
  nextProps: any,
  renderExpirationTime,
) {
  // 获取两个 context 先跳过
  const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);
  const context = getMaskedContext(workInProgress, unmaskedContext);

  let nextChildren;
  prepareToReadContext(workInProgress, renderExpirationTime);
  // 跳过 DEV 相关
  if (__DEV__) {
    ReactCurrentOwner.current = workInProgress;
    ReactCurrentFiber.setCurrentPhase('render');
    nextChildren = Component(nextProps, context);
    ReactCurrentFiber.setCurrentPhase(null);
  } else {
    // 这里的 Component 就是组件的方法
    // 调用 Component 方法的时候传入 nextProps, context 两个参数
    // context 这个在 官网API文档中没有提及
    // 可以在 function component 中获取到 child组件的 contextTypes 属性,也就是组件加上这个属性并配置props
    // 组件内就可以获取上层传递过来的 context 
    nextChildren = Component(nextProps, context);
  }

  // React DevTools reads this flag.
  // 注意这里
  workInProgress.effectTag |= PerformedWork;
  reconcileChildren(
    current,
    workInProgress,
    nextChildren,
    renderExpirationTime,
  );
  // 这里 return 的是 child, 说明 在 reconcileChildren 很可能处理 child
  return workInProgress.child;
}
  • 关于 workInProgress.effectTag |= PerformedWork; 这种操作
    • 在 ReactEffectTags.js 文件中, 有所有可能产生effect的值
    • 这里都是二进制的,每个值的1所在位置都是不一样的
    • 通过逻辑操作,&, | 的联合判断是否有某个特性
    • 上面 PerformedWork 本质是没有什么意义的
    • 是给 DevTools 说明这个组件在渲染中有更新
  • 关于 reconcileChildren 是通用的调节子节点的核心流程,这块先跳过
相关推荐
俊昭喜喜里25 分钟前
理解全局跨域CORS配置
前端
锋行天下3 小时前
DeepSeek写Langgraph就是个大傻逼,一本正经胡说八道
前端·人工智能·后端
jktantan3 小时前
每个节点 41 字节:把一棵百万节点树拆进 14 个 typed array
前端·javascript·vue.js·算法·typescript
计算机魔术师4 小时前
Anthropic官方插件被「寄生」,背后是同一类攻击又来了
前端
我命由我123454 小时前
访客系统形式(有用户概念、无用户概念)
java·开发语言·前端·javascript·python·产品运营·产品经理
key_3_feng4 小时前
评估与对齐:Agent 自我进化的护栏
前端·数据库·agent
LaughingZhu5 小时前
Product Hunt 热榜 2026-10-30:Empacer、Scape、Floot in ChatGPT
java·前端·数据库·人工智能·chatgpt·notion
Lank_M5 小时前
抠图结果缩放后边缘发脏,该怪的不是插值
前端
jerrywus5 小时前
Skill、MCP、Workflow、Rules、Memory 有什么区别?拿几次真实开发任务讲清楚
前端·agent·claude
补码缩写5 小时前
canvas 与 sharp 缩放透明图:默认预乘,非预乘得拆通道
前端