本文源码解析react版本:17.0.3
1、Hook概述
Hook 是 React 16.8 的新增特性,它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。Hook的诞生,是为共享状态逻辑提供更好的原生途径。React官方文档,已经对hook进行了十分全面的介绍:
https://reactjs.org/docs/hooks-intro.html
2、 React Hook源码文件
文件位置:packages/react/src/ReactHooks.js
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* @flow
import type {Dispatcher} from 'react-reconciler/src/ReactInternalTypes';
import type {
MutableSource,
MutableSourceGetSnapshotFn,
MutableSourceSubscribeFn,
ReactContext,
} from 'shared/ReactTypes';
import type {OpaqueIDType} from 'react-reconciler/src/ReactFiberHostConfig';
import ReactCurrentDispatcher from './ReactCurrentDispatcher';
type BasicStateAction<S> = (S => S) | S;
type Dispatch<A> = A => void;
function resolveDispatcher() {
const dispatcher = ReactCurrentDispatcher.current;
if (__DEV__) {
if (dispatcher === null) {
console.error(
'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
' one of the following reasons:\n' +
'1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
'2. You might be breaking the Rules of Hooks\n' +
'3. You might have more than one copy of React in the same app\n' +
'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.',
// Will result in a null access error if accessed outside render phase. We
// intentionally don't throw our own error because this is in a hot path.
// Also helps ensure this is inlined.
return ((dispatcher: any): Dispatcher);
export function getCacheForType<T>(resourceType: () => T): T {
const dispatcher = resolveDispatcher();
// $FlowFixMe This is unstable, thus optional
return dispatcher.getCacheForType(resourceType);
export function useContext<T>(Context: ReactContext<T>): T {
const dispatcher = resolveDispatcher();
if (__DEV__) {
// TODO: add a more generic warning for invalid values.
if ((Context: any)._context !== undefined) {
const realContext = (Context: any)._context;
// Don't deduplicate because this legitimately causes bugs
// and nobody should be using this in existing code.
if (realContext.Consumer === Context) {
console.error(
'Calling useContext(Context.Consumer) is not supported, may cause bugs, and will be ' +
'removed in a future major release. Did you mean to call useContext(Context) instead?',
} else if (realContext.Provider === Context) {
console.error(
'Calling useContext(Context.Provider) is not supported. ' +
'Did you mean to call useContext(Context) instead?',
return dispatcher.useContext(Context);
export function useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
export function useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
const dispatcher = resolveDispatcher();
return dispatcher.useReducer(reducer, initialArg, init);
export function useRef<T>(initialValue: T): {|current: T|} {
const dispatcher = resolveDispatcher();
return dispatcher.useRef(initialValue);
export function useEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
const dispatcher = resolveDispatcher();
return dispatcher.useEffect(create, deps);
export function useLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
const dispatcher = resolveDispatcher();
return dispatcher.useLayoutEffect(create, deps);
export function useCallback<T>(
callback: T,
deps: Array<mixed> | void | null,
): T {
const dispatcher = resolveDispatcher();
return dispatcher.useCallback(callback, deps);
export function useMemo<T>(
create: () => T,
deps: Array<mixed> | void | null,
): T {
const dispatcher = resolveDispatcher();
return dispatcher.useMemo(create, deps);
export function useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
deps: Array<mixed> | void | null,
): void {
const dispatcher = resolveDispatcher();
return dispatcher.useImperativeHandle(ref, create, deps);
export function useDebugValue<T>(
value: T,
formatterFn: ?(value: T) => mixed,
): void {
if (__DEV__) {
const dispatcher = resolveDispatcher();
return dispatcher.useDebugValue(value, formatterFn);
export const emptyObject = {};
export function useTransition(): [boolean, (() => void) => void] {
const dispatcher = resolveDispatcher();
return dispatcher.useTransition();
export function useDeferredValue<T>(value: T): T {
const dispatcher = resolveDispatcher();
return dispatcher.useDeferredValue(value);
export function useOpaqueIdentifier(): OpaqueIDType | void {
const dispatcher = resolveDispatcher();
return dispatcher.useOpaqueIdentifier();
export function useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
const dispatcher = resolveDispatcher();
return dispatcher.useMutableSource(source, getSnapshot, subscribe);
export function useCacheRefresh(): <T>(?() => T, ?T) => void {
const dispatcher = resolveDispatcher();
// $FlowFixMe This is unstable, thus optional
return dispatcher.useCacheRefresh();
从源码中看出调用dispatcher函数进行初始化和更新
3、 Hooks初始化和更新
文件目录:packages/react-reconciler/src/ReactFiberHooks.new.js
export function renderWithHooks<Props, SecondArg>(
current: Fiber | null,
workInProgress: Fiber,
Component: (p: Props, arg: SecondArg) => any,
props: Props,
secondArg: SecondArg,
nextRenderLanes: Lanes,
): any {
renderExpirationTime = nextRenderExpirationTime;
currentlyRenderingFiber = workInProgress;
// 如果current的值为空,说明还没有hook对象被挂载
// 而根据hook对象结构可知,current.memoizedState指向下一个current
nextCurrentHook = current !== null ? current.memoizedState : null;
// 用nextCurrentHook的值来区分mount和update,设置不同的dispatcher
ReactCurrentDispatcher.current =
nextCurrentHook === null
// 初始化时
? HooksDispatcherOnMount
// 更新时
: HooksDispatcherOnUpdate;
// 此时已经有了新的dispatcher,在调用Component时就可以拿到新的对象
let children = Component(props, secondArg);
.....
return children;
3.1 初始化与更新
请参考:useState原理解析
参考资料:React技术揭秘
本文源码解析react版本:17.0.31、Hook概述Hook 是 React 16.8 的新增特性,它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。Hook的诞生,是为共享状态逻辑提供更好的原生途径。React官方文档,已经对hook进行了十分全面的介绍:https://reactjs.org/docs/hooks-intro.html2、 React Hook源码文件文件位置:packages/react/src/ReactHooks.js
文章目录源码分析:react hook 最佳实践(上篇)前言2条规则为什么?源码分析useState使用方式为什么?源码分析useEffect使用方式为什么?源码分析useMemo使用方式为什么?源码分析useCallback使用方式为什么?源码分析下篇介绍
源码分析:react hook 最佳实践(上篇)
本文从 mini React —— Preact 源码的角度,分析 Rea...
hooks是function组件渲染中的一个环节。作用是将一部分组件的数据处理逻辑独立出来,以渐进式方式的加入到函数组件中。
源码地址packages/react-reconciler/src/ReactFiberHooks.js
根据源码实现简易hookDemo的代码地址:src/hookDemo目录下的CommonDemo组件
来玩局游戏吧!
废话不多说,上图:
前段时间研究了一波React的渲染流程,内部机制的源码,阅读到一半的时候React终于推出了16.8.x的版本,主要带来的更新就是Hooks的新功能。相信已经有很多的使用教程或者源码阅读文章。那么我也来一个属于自己的阅读有感的文章,做一个记录吧。
其实React文档中也有说明了Hooks的提出主要是为了解决什么问题的。
React团队认为组件之间复用状态逻辑很难。
就以前React为了将一个组...