使用 React 钩子的 、 和 生命周期钩子componentDidMount
的componentDidUpdate
等价物是什么 ?componentWillUnmount
useEffect
4 回答
componentDidMount
将一个空数组作为第二个参数传递useEffect()
给仅在挂载时运行回调。
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/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
componentDidUpdate
componentDidUpdate()
在更新发生后立即调用。初始渲染不调用此方法。useEffect
在包括第一个渲染在内的每个渲染上运行。所以如果你想有一个严格等价的 as componentDidUpdate
,你必须使用useRef
来确定组件是否已经挂载过一次。如果您想更严格,请使用useLayoutEffect()
,但它会同步触发。在大多数情况下,useEffect()
应该足够了。
这个答案受到 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/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/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/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
来自React 文档:
如果熟悉 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博客中的措辞的帮助下,以及我自己的一些补充:
虽然您可以使用这些钩子,但它并不是完全等价的。与componentDidMount
and不同componentDidUpdate
,它将捕获道具和状态。因此,即使在回调内部,您也会看到特定渲染的道具和状态(这意味着在componentDidMount
初始道具和状态中)。如果您想查看“最新”的内容,可以将其写入 ref。但是通常有一种更简单的方法来构建代码,这样您就不必这样做了。返回的函数应该可以替代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
始终指向最新计数,而不是属于特定渲染的计数。
为了简单的解释,我想展示一个视觉参考
正如我们在上图中简单地看到的那样 -
组件DidMount:
useEffect(() => {
console.log('componentWillMount');
}, []);
组件更新:
useEffect(() => {
console.log('componentWillUpdate- runs on every update');
});
useEffect(() => {
console.log('componentWillUpdate - runs if dependency value changes ');
},[Dependencies]);
组件将卸载:
useEffect(() => {
return () => {
console.log('componentWillUnmount');
};
}, []);
这是React Hooks 常见问题解答中的一个很好的总结,列出了类生命周期方法的 Hooks 等效项:
constructor
:函数组件不需要构造函数。useState
您可以在调用中初始化状态。如果计算初始状态很昂贵,您可以将函数传递给useState
.
getDerivedStateFromProps
:在渲染时安排更新。
shouldComponentUpdate
:请参阅下面的React.memo 。
render
: 这是函数组件体本身。
componentDidMount
,componentDidUpdate
,componentWillUnmount
:useEffect
Hook 可以表达这些的所有组合(包括不太 常见的情况)。
componentDidCatch
和getDerivedStateFromError
:这些方法还没有Hook 等价物,但很快就会添加。
componentDidMount
useEffect(() => { /*effect code*/ }, []);
[]
将使效果仅在挂载时运行一次。通常你最好指定你的依赖。要具有与 相同的布局时序componentDidMount
,请查看useLayoutEffect
(在大多数情况下不需要)。
componentWillUnmount
useEffect(() => { /*effect code*/ ; return ()=> { /*cleanup code*/ } }, [deps]);
componentWillUnmount
对应于cleanup的效果。
componentDidUpdate
const mounted = useRef();
useEffect(() => {
if (!mounted.current) mounted.current = true;
else {
// ... on componentDidUpdate
}
});
要具有与 相同的布局时序componentDidUpdate
,请查看useLayoutEffect
(在大多数情况下不需要)。另请参阅这篇文章以更详细地了解componentDidUpdate
钩子等价物。