hooks
useState
const [state, setState] = useState(initialState);
最常用的 hook ,但是有两个注意点
- 如果你向 initialState 传递一个函数,它会被视作是初始化函数,react 会调用这个函数,并且将这个函数的返回值作为初始状态。初始函数应当是一个纯函数(它应当没有任何参数,而且应当幂等),这是为了保证你的不会制造出
accidential impurities
。 - react 会在严格模式下将这个 Initializer 调用两次。
- setState 可以接收一个函数,如果 setState 的入参不是一个函数,它在 React 18 下可能会被批量执行
useEffect
useEffect(setup, dependencies?)
第二常用的 hook,用于在 「自变量发生变化」后触发副作用。 useEffect 常用于组件首次挂载时需要发请求。(此时,Dependencies 为空数组) 在 setup 中可以返回一个函数,称之为 cleanup 函数。react 会在组件从 DOM 中 removed 之后调用 cleanup 函数。
在父子组件中,子组件的 useEffect 先触发,父组件的 useEffect 后触发。
useRef
const ref = useRef(initialValue);
useRef 常用于操作 DOM
也可以用于在重渲染之间保存状态(useState 是 useRef 的语法糖)
function App() {
const [foo, setFoo] = useState();
const isInitial = useRef(true);
useEffect(() => {
if (isInitial.current) {
isInitial.current = false;
return;
}
// 首次加载不触发,当 foo 发生变化再触发
doSomething();
}, [foo]);
}
useContext
const value = useContext(SomeContext);
useContext 是 context comsumer 的简写,同时,可以将其进一步简化,从而得到 useMode 之类的自定义 hook 。
在实际的项目中,我总结的最佳实践是:
- 搭配自定义 hook 使用,这样子组件只需要
useXXContext()
即可。 - 搭配 react-error-bounrdary 设置错误边界,这样会有更加清晰的错误提示。
useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init?)
useMemo
useMemo 用于在重渲染之间保存计算结果,这个计算结果(calculateValue)通常是耗时的计算函数。(如下图,calculateValue 的返回值,才是实际要 memorized 的值,也就是 cachedValue)
const cachedValue = useMemo(calculateValue, dependencies);
注意和 memo 区分
const MemoizedComponent = memo(SomeComponent, arePropsEqual?)
memo 的实际使用场景是:当父组件自身的 state 发生变化,此时父组件会发生重渲染,父组件的重渲染会带动子组价发生重渲染。如果我们并不希望此时子组件发生重渲染,那么可以使用 memo 包裹一下子组件。
useCallback
useCallback 用于在重渲染之间缓存函数定义
const cachedFn = useCallback(fn, dependencies);
有关 useMemo useCallback 和 memo 之间的正确使用姿势,我学习了这篇文章 useCallback 是 useMemo 的语法糖。
const foo = useMemo(() => () => doSomething(), [deps]);
// 等价于
const foo = useCallback(() => doSomething(), [deps]);
useImperativeHandler
用来定制传入 ref 的行为,最常见的例子是,点击编辑的时候,输入框获得焦点(focused)。
useLayoutEffect
在每次浏览器重绘之前触发的 hook ,对于性能有伤害。
典型的例子是:实现当 tooltip 不能在上方被放下时,放到下面。
而且尽量使用 useEffect 代替
useDebugValue
用于在 react devtool 上展示信息,没怎么用过暂不展开