使用像componentDidMount
这样的React钩子的componentDidUpdate
,componentWillUnmount
和useEffect
生命周期钩子的等价物是什么?
componentDidMount
将一个空数组作为第二个参数传递给useEffect()
,仅在mount上运行回调。
function ComponentDidMount() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
console.log('componentDidMount');
}, []);
return (
<div>
<p>componentDidMount: {count} times</p>
<button
onClick={() => {
setCount(count + 1);
}}
>
Click Me
</button>
</div>
);
}
ReactDOM.render(
<div>
<ComponentDidMount />
</div>,
document.querySelector("#app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>
componentDidUpdate
更新发生后立即调用componentDidUpdate()
。初始渲染不会调用此方法。 useEffect
在每个渲染上运行,包括第一个渲染。因此,如果您想要与componentDidUpdate
具有严格的等价物,则必须使用useRef
来确定组件是否已安装一次。如果你想更加严格,使用useLayoutEffect()
,但它会同步发射。在大多数情况下,useEffect()
应该足够了。
这个answer is inspired by Tholle,所有功劳归于他。
function ComponentDidUpdate() {
const [count, setCount] = React.useState(0);
const isFirstUpdate = React.useRef(true);
React.useEffect(() => {
if (isFirstUpdate.current) {
isFirstUpdate.current = false;
return;
}
console.log('componentDidUpdate');
});
return (
<div>
<p>componentDidUpdate: {count} times</p>
<button
onClick={() => {
setCount(count + 1);
}}
>
Click Me
</button>
</div>
);
}
ReactDOM.render(
<ComponentDidUpdate />,
document.getElementById("app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>
componentWillUnmount
在useEffect的回调参数中返回一个回调函数,它将在卸载之前调用。
function ComponentWillUnmount() {
function ComponentWillUnmountInner(props) {
React.useEffect(() => {
return () => {
console.log('componentWillUnmount');
};
}, []);
return (
<div>
<p>componentWillUnmount</p>
</div>
);
}
const [count, setCount] = React.useState(0);
return (
<div>
{count % 2 === 0 ? (
<ComponentWillUnmountInner count={count} />
) : (
<p>No component</p>
)}
<button
onClick={() => {
setCount(count + 1);
}}
>
Click Me
</button>
</div>
);
}
ReactDOM.render(
<div>
<ComponentWillUnmount />
</div>,
document.querySelector("#app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>
来自React docs:
如果您熟悉React类生命周期方法,则可以将useEffect Hook视为componentDidMount,componentDidUpdate和componentWillUnmount的组合。
通过这个说他们的意思是:
componentDidMount是useEffect(callback, [])
的一种
componentDidUpdate是useEffect(callback, [dep1, dep2, ...])
的一种 - deps数组告诉React:“如果其中一个deps发生了变化,则在渲染后运行回调”。
componentDidMount + componentDidUpdate是useEffect(callback)
的一种
componentWillUnmount是回调函数的返回函数:
useEffect(() => {
/* some code */
return () => {
/* some code to run when rerender or unmount */
}
)
在Dan Abramov的blog短语的帮助下,以及我自己的一些补充:
虽然你可以使用这些钩子,但它并不完全等同。与componentDidMount
和componentDidUpdate
不同,它将捕获道具和状态。所以即使在回调中,你也会看到特定渲染的道具和状态(这意味着在componentDidMount
中最初的道具和状态)。如果你想看到“最新”的东西,你可以把它写到参考。但是通常有一种更简单的方法来构建代码,这样您就不必这样做了。假设替换componentWillUnmount
的返回函数也不是精确等价的,因为每次组件重新渲染时以及组件卸载时函数都会运行。请记住,效果的心理模型与组件生命周期不同,尝试找到它们的确切等效项可能会让您感到困惑,而不仅仅是帮助。为了提高效率,您需要“思考效果”,并且他们的心理模型更接近于实现同步而不是响应生命周期事件。
Dan的博客示例:
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
setTimeout(() => {
console.log(`You clicked ${count} times`);
}, 3000);
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
如果我们使用类实现:
componentDidUpdate() {
setTimeout(() => {
console.log(`You clicked ${this.state.count} times`);
}, 3000);
}
this.state.count
总是指向最新的计数,而不是属于特定渲染的计数。