你知道事实上 useState
和 useReducer
在 React 源码中是同一个方法吗?
固然, React 为你提供了单独的调用 useState
或 useReducer
的接口方法:
// source: https://github.com/facebook/react/blob/main/packages/react/src/ReactHooks.js
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);
}
复制代码
然而 React 内部在 mount
和 update
过程中, 调用的实际上是同一个方法:
// source: https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.new.js
function updateState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
// `updateState` 调用的实际上是传入了默认 `basicStateReducer` 方法的 `updateReducer`
return updateReducer(basicStateReducer, (initialState: any));
}
//这里就是默认的 reducer 方法:
function basicStateReducer<S>(state: S, action: BasicStateAction<S>): S {
return typeof action === 'function' ? action(state) : action;
}
复制代码
因此,你完全可以通过 useState
自己实现一个 useReducer
hook:
import { useState } from 'react'
// 你只需传入 `reducer` 参数,替换掉 `basicStateReducer` 方法即可:
export function useReducer(reducer, initialState) {
const [state, setState] = useState(initialState)
const dispatch = (action) => {
setState(prevState => reducer(prevState, action))
}
return [state, dispatch]
}
复制代码
除此之外,我们甚至可以用 useState
来实现 useRef
hook:
export function useRef(initialValue) {
// 你可以把 `ref` 当作不更新的 `state` 来看待
const [ref, unused] = useState({ current: initialValue });
return ref;
}
复制代码
在我们使用 React 进行编程时, useRef
这类 hook
被称为 逃生舱(Escape Hatches)。useEffect
也属于此类 , 因为它可以让你跳脱到 React 自动渲染更新的逻辑之外运行 DOM 操作等一系列所谓 “副作用” 的代码。
假如你从不使用 setState
方法来更新某个 state
,这个对象内部的信息就可以在 React 的多次渲染中得以保存,这样的 state
就可以起到与 ref
相同的作用。
事实上,上述的两个用 useState
实现 useReducer
和 useRef
的示例都是出现在 React 的 beta 文档 当中的。
beta 版文档的整体架构已经编写完成,阅读体验相较于旧版文档也更加丝滑,概念由浅入深,每章节末尾还附送在线习题,整体感觉和 Vue 的新版文档不分伯仲:
扫描二维码关注公众号,回复:
14475968 查看本文章

(总感觉前端就和 counter
todo
之类的例子过不去了...)
你也可以暂时在 beta react 中文文档 阅读,当然目前还没有完整翻译。
最后也希望有能力的同学一起参与到 react 中文文档 的翻译工作中来,做一点微小的贡献~