前言:
在查阅react官方文档时,发现它一会说useEffect return的clearup函数是在组件销毁时运行,一会又说clearup函数在dom渲染更新之后会执行,带着这个疑问,进行了以下探索。
react原文:
clearup函数是在组件销毁时运行:
为什么要在 effect 中返回一个函数? 这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数。如此可以将添加和移除订阅的逻辑放在一起。它们都属于 effect 的一部分。
React 何时清除 effect? React 会在组件卸载的时候执行清除操作。正如之前学到的,effect 在每次渲染的时候都会执行。这就是为什么 React 会在执行当前 effect 之前对上一个 effect 进行清除。
clearup函数在dom渲染更新之后会执行:
并不需要特定的代码来处理更新逻辑,因为 useEffect 默认就会处理。它会在调用一个新的 effect 之前对前一个 effect 进行清理。为了说明这一点,下面按时间列出一个可能会产生的订阅和取消订阅操作调用序列:
// Mount with { friend: { id: 100 } } props
ChatAPI.subscribeToFriendStatus(100, handleStatusChange); // 运行第一个 effect
// Update with { friend: { id: 200 } } props
ChatAPI.unsubscribeFromFriendStatus(100, handleStatusChange); // 清除上一个 effect
ChatAPI.subscribeToFriendStatus(200, handleStatusChange); // 运行下一个 effect
// Update with { friend: { id: 300 } } props
ChatAPI.unsubscribeFromFriendStatus(200, handleStatusChange); // 清除上一个 effect
ChatAPI.subscribeToFriendStatus(300, handleStatusChange); // 运行下一个 effect
// Unmount
ChatAPI.unsubscribeFromFriendStatus(300, handleStatusChange); // 清除最后一个 effect
effect是什么(展开)
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
}
我们声明了 count state 变量,并告诉 React 我们需要使用 effect。紧接着传递函数给 useEffect Hook。此函数就是我们的 effect。
那么到底是什么时候去执行effect的清除操作呢?
以下这个demo可以通过点击事件更新state值触发dom更新,通过路由跳转触发组件销毁
useEffect:
这个箭头函数就是 effect ,每个 effect 都可以返回一个清除函数。
useEffect(() => {
console.log('useEffect Todo');
return function clearup () {
console.log('useEffect clearup');
}
})
展开完整代码UseEffect.jsx
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
function UseEffect () {
const [count, setCount] = useState(0)
useEffect(() => {
//Dom初次渲染/更新,渲染完成之后调用
console.log('useEffect Todo');
return function clearup () {
// effect清除前、组件销毁前 调用该方法
console.log('useEffect clearup');
}
})
return (
<div>
<h3>useEffect</h3>
<span>已点击{count}次</span>
<button onClick={() => setCount(count + 1)}>点击</button>
<nav>
<Link to="/test">路由跳转</Link>
</nav>
</div>
);
}
export default UseEffect;
初次渲染
初次渲染时,只执行effect内容
组件更新
点击按钮,触发state更新,dom更新渲染完成之后,执行useEffect
这里每次我们重新渲染,都会生成新的 effect,替换掉之前的。
第二次点击,触发state更新,相当于重复第一次
由此可见,当组件初次渲染时,是执行effect内容; 当组件更新时,执行useEffect会将上一次的effect清除,清除时会执行clearup函数,执行下一个effect。
组件销毁
那组件销毁时,执行的是哪些呢?
点击路由跳转,来模拟组件销毁的状况
组件销毁时,只调用了effect return的clearup函数
总结:
初次渲染时,执行effect内容,dom更新后,执行上一个effect return的函数和新的effct的内容,组件销毁时,执行effect return的函数
/* 控制台 */
useEffect Todo//初次渲染
useEffect clearup//点击button:第一次更新dom之后,清除上一个effect
useEffect Todo//点击button:第一次更新dom之后,运行下一个effect
useEffect clearup//第二次更新dom之后,清除上一个effect
useEffect Todo//第二次更新dom之后,运行下一个effect
......
组件销毁
/* 控制台 */
useEffect clearup