特性
- useEffect是在渲染完成后触发
- useEffect是异步触发
引起的问题
多次渲染
const [count, setCount] = useState(0);
const [other, setOther] = useState(0);
const addCount = () => {
setCount(prev => prev + 1);
}
useEffect(() => {
setOther(count + 1);
}, [count]);
当执行addCount时,组件触发两次渲染
频繁触发的场景
此类问题需要模拟一个购物场景来进行说明:
现有商品列表组件、优惠券组件
优惠券组件中useEffect用于监听勾选商品时,默认勾选最大可用优惠券
当对商品频繁进行勾选、取消操作时,因为useEffect异步触发的机制
每次改变商品列表的操作,都会触发后续的关联操作
在例如此类的场景下,若相应的逻辑过多,又有多次渲染的问题,当机器的性能较差
就会出现比较严重的操作与展示不同步问题
一些适用or不适用的场景?
事件监听
在一些八杆子打不着的组件间,有使用事件系统进行通信的操作
useEffect在官网上也给出了事件监听的例子
然后,理所当然的就这么使用了
如果在较深层组件中使用事件进行通信,会降低代码的可读性
如果再进一步的滥用事件通信,那对项目的维护,就会造成巨大的影响
个人的理解是,能不用事件就尽量不用,如果非得用,也需要尽量的放到组件的外层
代替class组件的componentDidUpdate生命周期
function App({count}) {
const [copy, setCopy] = useState(count + 1);
useEffect(() => {
setCopy(count + 1);
}, [count]);
//....
return null;
}
这应该也是种常见的用法,根据props来初始化组件自身的某些state
函数式组件其实已经在弱化生命周期的概念
如果组件内部的state逻辑,需要依赖外部的传参,可以考虑使用props+state的方式
不一定非要把所有的逻辑都放到state上,再去处理props变化的问题
或者redux、useContext该用的用起来
为组件设置status并监听
enum EStatus {
loading,
error,
normal
}
const [status, setStatus] = useState(EStatus.loading);
useEffect(() => {
if (EStatus.loading === status) {
fetch();
}
if (EStatus.error === status) {
// 上传个埋点
}
}, [status]);
这是我之前使用较多的一种场景,原本的想法是把组件的不同状态封装起来
随着项目的维护,这个逻辑也开始被滥用了:
先改这里,再改那里,最后把status改为loading
这里的逻辑看似与其他逻辑解耦了
但是大部分场景,引起状态变化的地方都是要处理相应的逻辑
其他地方处理完了,这里再处理一次,总归是有点多余
因为这里的逻辑固定了,当需要扩展时,也需要相应的修改
最后要改的代码反而变成1+1>2
总结
- useEffect从设计上来说,功能是非常强大的
- 可能也是考虑到要对class组件的兼容
- 但很多时候,并不是能做到这么些事情,就要这么去做
假如一开始,就没有useEffect
那么说不定,我的代码运行的会更快
注:由于技术能力有限,以上内容仅为个人经验总结,并无相关可考