useEffect
在 React 中,useEffect 是一个用于处理副作用的 Hook。useEffect 接受两个参数:第一个参数是一个函数,用于执行副作用逻辑,第二个参数是一个数组,用于指定依赖项。
当依赖项数组为空(即不传递)时,useEffect 中的副作用逻辑只会在组件首次渲染时执行,而不会在之后的渲染中再次执行。
1. 🤔 如何用useEffect模拟componentDidMount生命周期?
对于这个问题,大家会习惯性的想到useEffect(()=>{fetchData()}),[]),将依赖项数组置为空即可,这是一个管用的方法,可是这个问题是个陷阱。函数组件和class组件的心智模型是不一样的,不能把他们混为一谈,在我看来,他们最大的区别是当状态变化时,函数组件相当于经历了轮回,从种子长成花朵,再从花朵结成种子,不同年份的花朵看起来一样,但终究不是同一朵,而class组件相当于一朵花,从鲜艳的花朵变成干花束,形态不同,但始终是那一朵。
2. 🤔 如何正确地在useEffect里请求数据?[]又是什么?
每个useEffect都是不同的,随着状态的变化,一个个effect出生,一个个effect死去,怎么保证出生的effect是我们想要的呢,这就需要借助依赖数组来注入遗传因子,请求过程中用到的所有的遗传因子都要写到数组里,当然这是最保险的方法,如果想更优雅一些,可以看引用文献及下面的实践总结。
3. 🤔 我应该把函数当做effect的依赖吗?
可以把函数作为effect的依赖。更多关于函数的最佳实践看下面的实践总结。
4. 🤔 为什么有时候会出现无限重复请求的问题?
分为两种情况,一种是没有依赖数组,那么每次渲染都会触发这个副作用,例如
useEffect(()=>{
fetchData()
})
还有一种是设置了依赖数组,但是依赖数组里的变量一直在变,例如
scss
复制代码const [data,setData] = useState()
useEffect(()=>{
const fetchData = async() => {
const res = await fetchNewData()
setData(res.data)
}
fetchData()
},[data])
5. 🤔 为什么有时候在effect里拿到的是旧的state或prop?
effect里获取的始终应该是最新的state或prop,如果出现旧的state或prop,一定是因为依赖数组中的依赖项不完整,没能触发effect更新。
useEffect最佳实践总结
1.class组件和函数组件的区别
- 每一个函数、每一个useEffect中的props和state都是独立的。不是state在不变的effect中变化,而是每一个effect中有不变的state
- 函数组件的状态会停留在某个状态,改变后的状态跟前者不是同一个,所以不同时机不同状态;class组件中,状态始终指向this.state,不同时机但是同一个状态
- useEffect并不等于componentDidmount + componentDieUpdate,将函数传入到子组件,如何仅在需要的时候触发这个请求,是分辨两者的最佳办法,函数式组件传入的函数是类的一个属性,是永远不会变的,他永远只会请求一次数据,如果传入它的依赖参数,依赖参数默认是一直变动的,所以就会一直重新请求数据。如果用hooks传递,设置好适当的依赖项,就只会在依赖项变动的时候重新请求数据
- useEffect先渲染,后执行preState和curState的副作用
2. 如何定义函数和请求
- 某些函数只在effect中使用的话,那就在effect里定义
- 某些函数在多个地方用到,就独立定义,最好用useCallBack包裹,并且在依赖数组里把依赖项写全
- useEffect回调函数不能用async修饰,但是可以在回调函数内部重新写一个async函数,然后调用
scss
复制代码 //不可以
useEffect(async()=>{
const res = await fetchNewData(id)
setData(res.data)
},[id])
//推荐
useEffect(()=>{
const fetchData = async() => {
const res = await fetchNewData(id)
setData(res.data)
}
fetchData()
},[id])