本文已参与「新人创作礼」活动,一起开启掘金创作之路。
useEffect
在类组件中,componentDidMount 和componentDidUpdate表示组件的挂载和更新生命周期,我们可以在这期间做一些逻辑处理,但是函数组件中并没有生命周期的相关函数。
useEffect(() => {
//effect
return () => {
//cleanup
}
}, [input])
函数组件中使用useEffect来弥补没有生命周期的问题。
const [count, setCount] = useState(0);
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
此时点击按钮,页面的标题也会改变。
useEffect 做了什么?
通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它。在这个 effect 中,我们设置了 document 的 title 属性,不过我们也可以执行数据获取或调用其他命令式的 API。
无需清除的effect
有时候,我们只想在 React 更新 DOM 之后运行一些额外的代码。 比如发送网络请求,手动变更 DOM,记录日志,这些都是常见的无需清除的操作。
需要清除的effect
之前,我们研究了如何使用不需要清除的副作用,还有一些副作用是需要清除的。例如订阅外部数据源。这种情况下,清除工作是非常重要的,可以防止引起内存泄露!
import React, { useState, useEffect } from 'react'
export default function App() {
const [state, setstate] = useState(0)
useEffect(() => {
const timer = setInterval(() => {
setstate(prev => prev + 1)
}, 1000)
// 清除定时器
return () => clearInterval(timer)
}, [])
return (
<div>{state}</div>
)
}
上面的代码就是在useEffect中定义定时器,并且能够清除定时器,防止内存泄漏。
为什么要在 effect 中返回一个函数?
这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数。如此可以将添加和移除订阅的逻辑放在一起。它们都属于 effect 的一部分。 清理函数会在组件卸载时以及下一次副作用函数调用之前执行
React 何时清除 effect?
React 会在组件卸载的时候执行清除操作。正如之前学到的,effect 在每次渲染的时候都会执行。这就是为什么 React 会在执行当前 effect 之前对上一个 effect 进行清除。
跳过 Effect 进行性能优化
在某些情况下,每次渲染后都执行清理或者执行 effect 可能会导致性能问题。在 class 组件中,我们可以通过在 componentDidUpdate 中添加对 prevProps 或 prevState 的比较逻辑解决:
componentDidUpdate(prevProps, prevState) {
if (prevState.count !== this.state.count) {
document.title = `You clicked ${this.state.count} times`;
}
}
如果某些特定值在两次重渲染之间没有发生变化,你可以通知 React 跳过对 effect 的调用,只要传递数组作为 useEffect 的第二个可选参数即可:
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新
如果 count 的值是 5,而且我们的组件重渲染的时候 count 还是等于 5,React 将对前一次渲染的 [5] 和后一次渲染的 [5] 进行比较。因为数组中的所有元素都是相等的(5 === 5),React 会跳过这个 effect,这就实现了性能的优化。