React Hooks:usePrevious
今日内容要点
- 认识类的组件的 componentDidUpdate
- 实现 usePrevious hook
- 结合 TypeScript 封装 usePrevious
- 总结
前言
在项目中某些情况下,我们必须知道组件的先前状态,通过对比状态去做一些事情。
在类组件编程中,我们可以通过 componentDidUpdate 这个生命周期钩子来做到实现,但函数组件却没有这个功能,所以我们需要自己编写自定义的逻辑来实现这个功能。
我们暂且把这个组件叫做 usePrevious(),顺便说一下,它甚至可能最终出现在下一个 React 版本中,请看 官方 React 文档中所述
。
认识类的组件的 componentDidUpdate
componentDidUpdate 的经典模版语法长成下面这样:
componentDidUpdate(prevProps, prevState, snapshot) {
// 典型用法 一定要出现 if 条件语句,否则容易死循环:
}
componentDidUpdate() 会在更新后会被立即调用,首次渲染不会执行此方法。当组件更新后,可以在此处对 DOM 进行操作。
一般我们会在此对更新前后的 props 进行了比较,选择在此处进行网络请求。(例如,当 props 未发生变化时,则不会执行网络请求)。
componentDidUpdate(prevProps) {
// 典型用法(不要忘记比较 props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}
有时,我们还会在 componentDidUpdate 中直接调用 setState(),但一定一定要注意它必须被包裹在一个条件语句里,不然会导致死循环或导致额外的重新渲染,虽然用户不可见,但会影响组件性能。
componentDidUpdate 生命周期钩子,它按以下顺序接受以下参数:
- prevProps 一个包含 props 先前值的对象
- prevState 包含先前状态值的对象
- snapshot 接收 getSnapshotBeforeUpdate 生命周期方法返回的值,如果没有返回值则是未定义 undefined。
实现 usePrevious hook
在函数式组建中,没有任何自带的钩子可以让我们获得之前的状态,但是我们可以使用 useRef() 这个 API 实现类似的功能。
创建一个名为 usePrevious.jsx
的新文件,内容如下:
import { useRef, useEffect } from "react";
const usePrevious = value => {
const ref = useRef();
// useEffect 是副作用,所以会先执行 return ,然后在执行 useEffect,ref.current 的值正好完了一步。
useEffect(() => {
ref.current = value;
});
return ref.current;
};
export default usePrevious;
使用案例:
const Counter = () => {
const [value, setValue] = React.useState(0);
const lastValue = usePrevious(value);
return (
<div>
<p>
Current: {value} - Previous: {lastValue}
</p>
<button onClick={() => setValue(value + 1)}>Increment</button>
</div>
);
};
在这我们能明显的感觉到 usePrevious 相对于 componentDidUpdate 的简单易维护。
结合 TypeScript 封装 usePrevious
如果项目支持 TypeScript,我们还需要向自定义钩子添加一些类型:
import { useRef, useEffect } from "react";
const usePrevious = <T>(value: T): T | undefined => {
const ref = useRef<T>();
useEffect(() => {
ref.current = value;
});
return ref.current;
};
export default usePrevious;
简单的添加了函数泛型和联合类型。
总结
在本文中,我们学习了如何在 React 中获取功能组件的先前状态,对于类组件可通过 componentDidUpdate 来实现,在函数组件中需要基于内置的 useRef 创建了自定义 usePrevious hook,如果是 React 的项目,我们还为 usePrevious 添加了类型校验。
2021-07-28 17:35