React
React是一个用于构建用户界面的JavaScript库。
react常用的hooks
React Hooks是React 16.8版本引入的新特性,它允许我们在不编写类组件的情况下使用状态和其他React特性。下面是一些React中常用的hooks的TSX实现:
- useState
用于管理组件状态。
import React, { useState } from 'react';
function Counter() {
// 声明一个名为count的状态变量,初始值为0
const [count, setCount] = useState<number>(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
- useEffect
用于处理副作用,如数据获取、订阅或手动修改DOM。
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState<number>(0);
// 相当于componentDidMount和componentDidUpdate
useEffect(() => {
// 更新文档标题
document.title = `You clicked ${count} times`;
// 清理函数,相当于componentWillUnmount;在依赖项count改变时副作用函数执行前调用
return () => {
console.log('Component will unmount');
};
}, [count]); // 仅在count改变时执行
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
- useContext
用于访问上下文,避免 props drilling。
import React, { useContext, createContext } from 'react';
// 创建上下文
const ThemeContext = createContext<'light' | 'dark'>('light');
function ThemedButton() {
// 访问上下文
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme === 'dark' ? '#333' : '#fff', color: theme === 'dark' ? '#fff' : '#333' }}>
{theme === 'dark' ? 'Dark Mode' : 'Light Mode'}
</button>
);
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
);
}
- useReducer
用于更复杂的状态管理,类似于Redux。
import React, { useReducer } from 'react';
// 定义状态类型
interface CounterState {
count: number;
}
// 定义动作类型
type CounterAction =
| { type: 'increment' }
| { type: 'decrement' };
// 定义reducer函数
function counterReducer(state: CounterState, action: CounterAction): CounterState {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error('Unexpected action');
}
}
function Counter() {
// 使用useReducer
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}
- useRef
用于访问DOM元素或保存可变值。
import React, { useRef, useEffect } from 'react';
function TextInputWithFocusButton() {
// 创建ref
const inputEl = useRef<HTMLInputElement>(null);
const focusInput = () => {
// 访问DOM元素
inputEl.current?.focus();
};
return (
<div>
<input ref={inputEl} type="text" />
<button onClick={focusInput}>Focus the input</button>
</div>
);
}
- useCallback
用于缓存函数引用,避免不必要的重新渲染。
import React, { useState, useCallback } from 'react';
interface ButtonProps {
onClick: () => void;
children: React.ReactNode;
}
function Button({ onClick, children }: ButtonProps) {
console.log('Button re-rendered');
return <button onClick={onClick}>{children}</button>;
}
function App() {
const [count, setCount] = useState<number>(0);
// 缓存函数
const increment = useCallback(() => {
setCount(count + 1);
}, [count]);
return (
<div>
<p>Count: {count}</p>
<Button onClick={increment}>Increment</Button>
</div>
);
}
- useMemo
用于缓存计算结果,避免不必要的重复计算。
import React, { useState, useMemo } from 'react';
interface ExpensiveCalculationProps {
num: number;
}
function ExpensiveCalculation({ num }: ExpensiveCalculationProps) {
// 缓存计算结果
const result = useMemo(() => {
console.log('Calculating...');
return num * 2;
}, [num]);
return <div>Result: {result}</div>;
}
function App() {
const [count, setCount] = useState<number>(0);
const [num, setNum] = useState<number>(10);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<p>Num: {num}</p>
<button onClick={() => setNum(num + 1)}>Increment Num</button>
<ExpensiveCalculation num={num} />
</div>
);
}
- useLayoutEffect
用于在DOM更新后同步执行副作用,类似于useEffect但执行时机不同。
import React, { useRef, useLayoutEffect } from 'react';
function LayoutEffectExample() {
const ref = useRef<HTMLDivElement>(null);
useLayoutEffect(() => {
if (ref.current) {
const rect = ref.current.getBoundingClientRect();
console.log('Element position:', rect);
}
}, []);
return <div ref={ref}>Hello World</div>;
}
- useDebugValue
用于在React开发者工具中显示自定义hook的标签。
import { useDebugValue, useState } from 'react';
function useCounter(initialValue: number) {
const [count, setCount] = useState<number>(initialValue);
// 在开发者工具中显示标签
useDebugValue(`Count: ${count}`);
return [count, setCount] as const;
}
function Counter() {
const [count, setCount] = useCounter(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
react hooks原理
hooks的数据结构
每个组件都有一个hooks链表,每个hook对应一个Hook对象。
Hooks以链表形式存储在Fiber节点的memoizedState
上。
源码位置- memoizedState:
- useState:保存当前状态值
- useEffect:保存 { create, destroy, deps, tag } 对象
- useRef:保存 { current } 对象
tstype Hook = { memoizedState: any, // 存储当前状态(state/effect/deps等) baseState: any, // 更新计算的基础状态 baseQueue: Update<any, any> | null, // 未处理的更新队列 queue: UpdateQueue<any, any> | null, // 更新队列(存储 setState 的 action) next: Hook | null, // 指向下一个 Hook(形成链表) };
1.1 useState 实现
通过Fiber.memoizedState判断是否是mount阶段,如果是mount阶段,就调用mountState,否则调用updateState。
以下是mount阶段伪代码,mountState源码jsfunction mountState(initialState) { // 1. 创建新的Hook对象 const hook = mountWorkInProgressHook(); // 2. 初始化状态 hook.memoizedState = initialState; // 3. 创建更新队列 const queue = { pending: null, dispatch: null, lastRenderedState: initialState }; hook.queue = queue; // 4. 创建dispatch函数(绑定Fiber和队列) const dispatch = (queue.dispatch = dispatchSetState.bind( null, currentlyRenderingFiber, queue )); return [hook.memoizedState, dispatch]; }
以下是update阶段伪代码,updateState源码
jsfunction updateState() { return updateReducer(basicStateReducer); } function updateReducer(reducer) { // 1. 获取现有Hook对象 const hook = updateWorkInProgressHook(); // 2. 处理更新队列 if (hook.queue.pending) { // ...计算新状态 } return [hook.memoizedState, hook.queue.dispatch]; }
1.2 useState 实现整体过程
- memoizedState:
react 渲染过程
初始化阶段react版本为19.1.0
- createRoot入口
以下是伪代码,createRoot源码
jsexport function createRoot(container, options) { // 验证容器有效性 if (!isValidContainer(container)) { throw new Error('Target container is not a DOM element.'); } // 创建FiberRoot和root const root = createContainer( container, ConcurrentRoot, // React 18默认并发模式 null, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError, transitionCallbacks, ); // 标记容器已被使用 container._reactRootContainer = root; // 绑定所有支持的事件 const rootContainerElement = container.nodeType === COMMENT_NODE ? container.parentNode : container; // React事件委托机制的基础,通过在根容器集中注册事件监听器,\n React能够实现高效的事件处理和合成事件系统,统一管理不同浏览器的事件兼容性问题 listenToAllSupportedEvents(rootContainerElement); return new ReactDOMRoot(root); }
- createContainer入口
创建 Fiber 根节点,初始化更新队列initializeUpdateQueue(HostRootFiber),FiberRoot.current = HostRootFiber
fiberRoot: 整个 React 应用的「根容器」,唯一一个。
rootFiber: 组件树的根节点对应的 Fiber 对象(HostRootFiber),可能存在多个。
以下是伪代码,createContainer源码
jsfunction createContainer( containerInfo: Container, tag: RootTag, hydrate: boolean, hydrationCallbacks: null | SuspenseHydrationCallbacks, ): FiberRoot { // 1. 创建 FiberRoot 实例 const root: FiberRoot = { containerInfo, // 真实 DOM 容器(如 div#root) current: null, // 当前激活的 Fiber 树(current 树) pendingLanes: NoLanes, // 待处理的更新优先级队列 // 其他全局状态... }; // 2. 创建 HostRootFiber(根 Fiber 节点) const uninitializedFiber = createHostRootFiber(tag); root.current = uninitializedFiber; // FiberRoot 关联 current 树 uninitializedFiber.stateNode = root; // Fiber 节点反向关联 FiberRoot return root; }
- 双缓冲机制
双缓冲机制是指在渲染过程中,使用两个缓冲区来存储中间结果,避免直接渲染到屏幕上导致的闪烁问题。
在更新过程中的commit阶段,最后root.current = workInProgressRootFiber,从而实现平滑的渲染效果。
Fiber数据结构
- createRoot入口
触发渲染
- 调用render
以下是伪代码,render源码
jsReactDOMRoot.prototype.render = function(children) { updateContainer(children, root, null, null); };
- updateContainer创建更新并触发调度 以下是伪代码,updateContainer源码
jsfunction updateContainer( element, container, parentComponent, callback, ){ // 1. 获取根 Fiber 节点(HostRootFiber) const current = container.current; // 2. 为初始更新分配优先级(同步优先级,确保立即执行) const lane = requestUpdateLane(current); // 3. 创建更新对象(内容为 <App /> 组件树) const update = createUpdate(lane, null, callback); update.payload = { element }; // 更新内容:待渲染的组件树 // 4. 加入更新队列 enqueueUpdate(current, update); // 5. 调度更新执行 scheduleUpdateOnFiber(current, lane, node); }
- 调用render
调度协调阶段
- 调度更新
以下是伪代码,scheduleUpdateOnFiber源码
jsfunction scheduleUpdateOnFiber(fiber, lane, eventTime) { //标记root 为更新状态 markRootUpdated(root, lane); // 确保根节点被调度(调度入口) ensureRootIsScheduled(root); }
jsfunction ensureRootIsScheduled(root) { // 触发微任务调度 ensureScheduleIsScheduled() }
以下是伪代码,ensureScheduleIsScheduled源码
jsfunction ensureScheduleIsScheduled() { // 执行微任务 if (!didScheduleMicrotask) { didScheduleMicrotask = true; scheduleImmediateRootScheduleTask(); } }
scheduleImmediateRootScheduleTask函数
环境不同,它可能会使用微任务(microtask)或者调度器(Scheduler)来处理根节点的调度
以下是伪代码,scheduleImmediateRootScheduleTask源码jsfunction scheduleImmediateRootScheduleTask() { // 1. 检查是否支持微任务 if (supportsMicrotasks) { // 2. 使用微任务调度 processRootScheduleInMicrotask(performRootSchedule); } else { // 3. 使用调度器调度 scheduleCallback(ImmediateSchedulerPriority, performRootSchedule); } }
本次环境默认进入微任务调度,不使用Schedule调度
调用processRootScheduleInMicrotask后,进入flushSyncWorkAcrossRoots_impl函数,处理同步工作
以下是伪代码,flushSyncWorkAcrossRoots_impl源码jsfunction flushSyncWorkAcrossRoots_impl(syncTransitionLanes, isDuringMicrotask) { // 1. 检查是否有同步工作 if (!mightHavePendingSyncWork) return; // 2. 重置标志 mightHavePendingSyncWork = false; // 3. 遍历所有根节点 let root = firstScheduledRoot; while (root !== null) { // 4. 检查是否需要同步处理 if ( syncTransitionLanes !== NoLanes || includesSyncLane(root.pendingLanes) || (enableGestureTransition && isGestureRender(root.pendingLanes)) ) { // 5. 执行同步工作 performSyncWorkOnRoot(root); } root = root.next; } }
- 调度更新
- 以下是performSyncWorkOnRoot到completeUnitOfWork的流程

- commit 阶段 completeUnitOfWork函数
完成工作单元的处理并向上回溯 Fiber 树
以下是伪代码,completeUnitOfWork源码jsfunction completeUnitOfWork(unitOfWork: Fiber): void { let completedWork: Fiber = unitOfWork; do { // 1. 检查未完成标志 if ((completedWork.flags & Incomplete) !== NoFlags) { unwindUnitOfWork(completedWork, ...); return; } // 2. 获取当前节点和父节点 const current = completedWork.alternate; const returnFiber = completedWork.return; // 3. 执行完成工作 const next = completeWork(current, completedWork, entangledRenderLanes); // 4. 处理新产生的工作 if (next !== null) { workInProgress = next; return; } // 5. 处理兄弟节点 const siblingFiber = completedWork.sibling; if (siblingFiber !== null) { workInProgress = siblingFiber; return; } // 6. 回溯到父节点 completedWork = returnFiber; workInProgress = completedWork; } while (completedWork !== null); // 7. 标记根节点完成 if (workInProgressRootExitStatus === RootInProgress) { workInProgressRootExitStatus = RootCompleted; } }
completeWork函数
创建/更新 DOM 节点并设置属性、构建 effect 链表供提交阶段使用
completeWork源码
commitRootWhenReady、commitRoot函数
在finishConcurrentRender函数中触发
提交根节点的 effect 链表,将 DOM 变更应用到真实 DOM 上
finishConcurrentRender源码commitRoot源码 以下是commitRoot函数的伪代码
function commitRoot(root) {
const finishedWork = root.finishedWork;
// 执行 BeforeMutation 阶段生命周期
// 读取当前 DOM 状态
commitBeforeMutationEffects(finishedWork);
// 执行 DOM 操作
// 插入/更新/删除节点
// 更新 DOM 属性
// 文本节点内容变更
commitMutationEffects(finishedWork, root);
// 切换当前 Fiber 树
root.current = finishedWork;
// 执行 Layout 阶段生命周期
// 生命周期:componentDidMount/componentDidUpdate
// Hook useLayoutEffect 回调
commitLayoutEffects(finishedWork, root);
// 清理工作
root.finishedWork = null;
}