React 实现 useState

本文将带大家实现 useState。

先看下如何使用。

js 复制代码
function FunctionComponent() {
  const [count1, setCount1] = useState(1);

  return (
    <div className="border">
      <button
        onClick={() => {
          setCount1(count1 + 1);
        }}
      >
        {count1}
      </button>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  (<FunctionComponent />) as any
);

useState 是基于 useReducer 实现的,参考文章 React 实现 useReducer

实现 useState

js 复制代码
// 源码中 useState 与 useReducer 对比:
// useState 如果 state 没有改变,不引起组件更新。useReducer 不是如此。(老的源码中,state 没有改变,两者都不更新)
// reducer 代表 state 修改规则,useReducer 比较方便复用这个规则
export function useState<S>(initialState: (() => S) | S) {
  const init = isFn(initialState) ? (initialState as any)() : initialState;
  return useReducer(null, init);
}

useReducer 修改

为了适配 useStateuseReducerdispatchReducerAction 两个函数的 reducer 参数增加了 null。

js 复制代码
export function useReducer<S, I, A>(
  reducer: ((state: S, action: A) => S) | null,
  initialArg: I,
  init?: (initialArg: I) => S
) {
    ...
}

function dispatchReducerAction<S, I, A>(
  fiber: Fiber,
  hook: Hook,
  reducer: ((state: S, action: A) => S) | null,
  action: any
) {
    ...
}

再聊 scheduleUpdateOnFiber

Fiber hooks 调用 scheduleUpdateOnFiber 时,第三个参数传的都是 true。

因为 React 考虑到 ensureRootIsScheduled 使用到了调度器,会增加复杂度。

js 复制代码
export function scheduleUpdateOnFiber(
  root: FiberRoot,
  fiber: Fiber,
  isSync?: boolean
) {
  workInProgressRoot = root;
  workInProgress = fiber;

  if (isSync) {
    // queueMicrotask 是 JS 原生 API
    queueMicrotask(() => performConcurrentWorkOnRoot(root));
  } else {
    ensureRootIsScheduled(root);
  }
}

export function performConcurrentWorkOnRoot(root: FiberRoot) {
  // 1. render, 构建 fiber 树,即 VDOM(beginWork|completeWork)
  renderRootSync(root);

  const finishedWork = root.current.alternate;
  root.finishedWork = finishedWork; // 根 Fiber

  // 2. commit, VDOM -> DOM
  commitRoot(root);
}
相关推荐
子兮曰24 分钟前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
竹林8181 小时前
用 The Graph 查询链上数据实战:从手搓 RPC 到 Subgraph,我的 NFT 项目数据加载快了 10 倍
前端·javascript
妙码生花1 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
Awu12272 小时前
⚡从零开发 Agent CLI(五)实现一个可治理、可扩展的工具系统
前端·人工智能·claude
咪库咪库咪3 小时前
Vue3-生命周期
前端
莪_幻尘3 小时前
你的 AI Skill 越多越蠢?Token 上下文爆炸的求生指南
前端·ai编程
lichenyang4533 小时前
从 has.echo 到异步 API 注册表:一次 ASCF API 回调不触发的排查复盘
前端
林瞅瞅4 小时前
Nuxt3 项目部署 Nginx 防盗链后特定 JS 文件 403 问题修复方案
前端
kyriewen4 小时前
别再每次都 Google 了:我整理了前端日常最常踩的 10 个 Git 坑,附速查表
前端·javascript·git
一颗奇趣蛋4 小时前
Web 视频开发完全指南:从入门到精通
前端