前言
useEffect(callback, dependencies) 是用于在函数式组件中处理副作用的钩子, callback 参数是一个函数,副作用的逻辑放到这个函数内部, dependencies 是副作用的依赖列表: 依赖项为 props 或 state 状态值。
useEffect 简单示例
useEffect(
() => {
console.log('I run when `a` changes')
},
[a]
)
useEffect 将在以下两种情况下运行:
- 组件首次挂载时
- 当变量
a改变时。
下面的例子将导致 useEffect 无限循环
const [count, setCount] = useState(0)
// 这里当 count 变化时执行 useEffect
// 又触发 count 改变函数,
// 然后又触发了useEffect
// 如此无限循环
useEffect(
() => {
setCount(count + 1)
},
[count]
)
这是一个简单的示例。实际场景中我们会有这样的代码:
const [userData, setUserData] = useState({
name: 'Jack',
friends: ['alice', 'bob'],
})
// 也会无限运行,原因与上述相同
useEffect(
() => {
const newUser = {
...userData,
friends: [...userData.friends, 'charlie'],
}
setUserData(newUser)
},
[userData]
)
这里我们 设置newUser 有两种方法:
setUserData(newUser)
setUserData(function(oldUser) {
const newUser = {}
return newUser
})
第一个获取新值并设置它。
第二个接受一个用旧值调用的函数,并返回新值。
让我们以前面的 useEffect 代码示例为例,将其更新为第二种形式:
const [userData, setUserData] = useState({
name: 'Jack',
friends: ['alice', 'bob'],
})
// 不会无限循环
useEffect(() => {
setUserData(oldUser => {
const newUser = {
...oldUser,
friends: [...oldUser.friends, 'charlie'],
}
return newUser
})
}, [])
这里我们不再需要依赖 userData ,因为我们从 setUserData 的回调函数中读取它!
这意味着我们的 useEffect 调用可以自由修改和设置新的用户数据而不用担心无限循环。
因此我们可以不用在 useEffect dependencies 数组中依赖他,这意味着当它改变时 useEffect 不会重新运行!
useEffect
副作用抽象本意是好的,也能看得出来官方想弱化生命周期的概念,但这太理想了,useEffect 包住所有副作用的想法也很 naive,佐证是后面的 useLayoutEffect,自己打自己脸,还不如一开始就分出多个 effect api。
React 会等待浏览器完成画面渲染之后才会延迟调用 useEffect
例子:改变css,改变块的位置,会出现拖影,一闪而过
可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
useEffect 调度的 effect 不会阻塞浏览器更新屏幕,也就是他是异步的
useLayoutEffect 是同步的,api相同
useEffect 不能是异步函数(回调函数中使用 async...await... 的时候,会报错)
全文完
谢谢!
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 15 天