React Hooks 和组件生命周期等价物
React Hooks and Component Lifecycle Equivalent
componentDidMount
、componentDidUpdate
和 componentWillUnmount
生命周期挂钩使用 useEffect
等 React 挂钩的等价物是什么?
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
运行s 在每个渲染上,包括第一个。所以如果你想有一个严格等同于 componentDidUpdate
,你必须使用 useRef
来确定组件是否已经安装了一次。如果你想更严格,使用 useLayoutEffect()
,但它会同步触发。在大多数情况下,useEffect()
应该足够了。
这个,所有的功劳都归于他。
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
Return 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 docs:
If you’re familiar with React class lifecycle methods, you can think
of useEffect Hook as componentDidMount, componentDidUpdate, and
componentWillUnmount combined.
这句话的意思是:
componentDidMount 有点像 useEffect(callback, [])
componentDidUpdate 有点像 useEffect(callback, [dep1, dep2, ...])
- deps 数组告诉 React:"if one of the deps is change, run the callback after rendering".
componentDidMount + componentDidUpdate 有点像 useEffect(callback)
componentWillUnmount 是回调返回的函数:
useEffect(() => {
/* some code */
return () => {
/* some code to run when rerender or unmount */
}
)
在 Dan Abramov's phrasing from his blog 的帮助下,以及我自己的一些补充:
虽然您可以使用这些钩子,但它们并不完全等同。与 componentDidMount
和 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>
);
}
如果我们使用 class 实现:
componentDidUpdate() {
setTimeout(() => {
console.log(`You clicked ${this.state.count} times`);
}, 3000);
}
this.state.count
始终指向 最新 计数,而不是属于特定渲染的计数。
这里是 React Hooks FAQ 列出 class 生命周期方法的 Hooks 等价物的一个很好的总结:
constructor
: Function components don’t need a constructor. You can initialize the state in the useState
call. If computing the initial state is expensive, you can pass a function to useState
.
getDerivedStateFromProps
: Schedule an update while rendering instead.
shouldComponentUpdate
: See React.memo below.
render
: This is the function component body itself.
componentDidMount
, componentDidUpdate
, componentWillUnmount
: The useEffect
Hook can express all combinations of these (including less common cases).
componentDidCatch
and getDerivedStateFromError
: There are no Hook equivalents for these methods yet, but they will be added soon.
componentDidMount
useEffect(() => { /*effect code*/ }, []);
[]
将在挂载时仅使效果 运行 一次。通常你最好specify your dependencies. To have the same layout timings as componentDidMount
, have a look at 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
(not needed in most cases). See also 以更详细地了解 componentDidUpdate
挂钩等价物。
为了简单的解释,我想展示一个视觉参考
正如我们在上图中可以简单地看到,对于 -
componentDidMount :
useEffect(() => {
console.log('componentWillMount');
}, []);
componentDidUpdate :
useEffect(() => {
console.log('componentWillUpdate- runs on every update');
});
useEffect(() => {
console.log('componentWillUpdate - runs if dependency value changes ');
},[Dependencies]);
componentwillUnmount :
useEffect(() => {
return () => {
console.log('componentWillUnmount');
};
}, []);
componentDidMount
、componentDidUpdate
和 componentWillUnmount
生命周期挂钩使用 useEffect
等 React 挂钩的等价物是什么?
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
运行s 在每个渲染上,包括第一个。所以如果你想有一个严格等同于 componentDidUpdate
,你必须使用 useRef
来确定组件是否已经安装了一次。如果你想更严格,使用 useLayoutEffect()
,但它会同步触发。在大多数情况下,useEffect()
应该足够了。
这个
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
Return 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 docs:
If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.
这句话的意思是:
componentDidMount 有点像 useEffect(callback, [])
componentDidUpdate 有点像 useEffect(callback, [dep1, dep2, ...])
- deps 数组告诉 React:"if one of the deps is change, run the callback after rendering".
componentDidMount + componentDidUpdate 有点像 useEffect(callback)
componentWillUnmount 是回调返回的函数:
useEffect(() => {
/* some code */
return () => {
/* some code to run when rerender or unmount */
}
)
在 Dan Abramov's phrasing from his blog 的帮助下,以及我自己的一些补充:
虽然您可以使用这些钩子,但它们并不完全等同。与 componentDidMount
和 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>
);
}
如果我们使用 class 实现:
componentDidUpdate() {
setTimeout(() => {
console.log(`You clicked ${this.state.count} times`);
}, 3000);
}
this.state.count
始终指向 最新 计数,而不是属于特定渲染的计数。
这里是 React Hooks FAQ 列出 class 生命周期方法的 Hooks 等价物的一个很好的总结:
constructor
: Function components don’t need a constructor. You can initialize the state in theuseState
call. If computing the initial state is expensive, you can pass a function touseState
.
getDerivedStateFromProps
: Schedule an update while rendering instead.
shouldComponentUpdate
: See React.memo below.
render
: This is the function component body itself.
componentDidMount
,componentDidUpdate
,componentWillUnmount
: TheuseEffect
Hook can express all combinations of these (including less common cases).
componentDidCatch
andgetDerivedStateFromError
: There are no Hook equivalents for these methods yet, but they will be added soon.
componentDidMount
useEffect(() => { /*effect code*/ }, []);
[]
将在挂载时仅使效果 运行 一次。通常你最好specify your dependencies. To have the same layout timings as componentDidMount
, have a look at 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
(not needed in most cases). See also componentDidUpdate
挂钩等价物。
为了简单的解释,我想展示一个视觉参考
正如我们在上图中可以简单地看到,对于 -
componentDidMount :
useEffect(() => {
console.log('componentWillMount');
}, []);
componentDidUpdate :
useEffect(() => {
console.log('componentWillUpdate- runs on every update');
});
useEffect(() => {
console.log('componentWillUpdate - runs if dependency value changes ');
},[Dependencies]);
componentwillUnmount :
useEffect(() => {
return () => {
console.log('componentWillUnmount');
};
}, []);