使用 React useEffect 挂钩的意外行为
Unexpected behaviour using React useEffect hook
我开始研究反应钩子。但我有一些疑问。我以为我明白了,但经验证据显示出意想不到的行为,至少据我所知是这样。
为了说明我的困惑或误解,我以实现一个简单时钟的classic练习为例。
下面是实现功能组件的代码。
import {useState, useEffect} from 'react';
const Clock = (props) => {
const {show, country, timezone} = props;
const t = Date.now () + 3600 * timezone * 1000;
const dateInitial = new date (t);
const [datE, setDate] = useState (dateInitial);
useEffect (() => {
const interval = setInterval (() => {
const t = date.getTime () + (1 * 1000);
setDate (new date (t));
}, 1000);
return () => {
// ONLY clears the return of this function
// When the component is unmounted from the DOM
console.log ("Cleanup function (componentWillUnmount ())");
clearTimeout (interval); // The setTimeout is cleared as soon as the component is unmounted from the DOM
}
}, [date);
return (
<h2 style = {{display: show? true: 'none'}}> Today in {country} is {date.toLocaleDateString () + '' + date.toLocaleTimeString ()} </h2>
)
};
export default Clock;
功能组件使用挂钩到“日期”状态的 useEffect 属性。
函数:
() => {
const t = date.getTime () + (1 * 1000);
setDate (new date (t));
}, 1000);
作为第一个参数传递给useEffect,应该用于componentDidMount和componentDidUpdate生命周期事件。
同时清理函数:
return () => {
// ONLY clears the return of this function
// When the component is unmounted from the DOM
console.log ("Cleanup function (componentWillUnmount ())");
clearTimeout (interval); // The setTimeout is cleared as soon as the component is unmounted from the DOM
}
应该在组件生命周期的componentWillUnmount事件中执行。
但是如果我“运行”我们的组件,我会在日志中看到:
如您所见,componentWillUnmount 事件每秒发生一次。如果我没记错的话,当组件从 DOM 中移除时,不应该发生 componentWillUnmount 吗?在这种情况下,我们只有 DOM 的新呈现,而不是从 DOM 中删除元素。我很困惑。另一方面,如果您使用 class 组件尝试以下示例:
Clock with class component (on codepen.io)
你会看到 console.log ("componentWillUnmount");从未出现过...
我还观察到,如果我更改选项卡,我在 post 中插入的组件会丢失几秒钟,而在 codepen.io 中插入的组件不会丢失“节拍”。
对不起,我有点困惑。
我提前感谢你总是宝贵的澄清。
useEffect 代表 componentDidMount 和 componentWillUnmount 只有当你给它一个空的依赖数组时:
useEffect(() => {
//code that will only be executed when component mount
return () => {
//code that will only executed when component unmount
}
}, [])
在你的例子中,你在依赖数组中有日期,这意味着,每次日期改变,一个新的执行,把它想象成 useEffect 是一个迷你组件,它的生命取决于日期值 -时间日期更改它卸载并重新安装。
在这种情况下我们需要 return 函数的原因是,例如当我们有一个依赖于日期值的侦听器时,所以每次我们需要删除日期更改使用旧值的旧侦听器并使用新值附加新侦听器。
useEffect(() => {
//We attach a listener which depends on date value
const listenerHandler = () => {console.log(date)}
window.addEventListener('event', listenerHandler)
return () => {
//We need to remove the listener with old value so we don't have many listeners attached each time date changes
window.removeEventListener('event', listenerHandler)
}
}, [date])
我开始研究反应钩子。但我有一些疑问。我以为我明白了,但经验证据显示出意想不到的行为,至少据我所知是这样。
为了说明我的困惑或误解,我以实现一个简单时钟的classic练习为例。 下面是实现功能组件的代码。
import {useState, useEffect} from 'react';
const Clock = (props) => {
const {show, country, timezone} = props;
const t = Date.now () + 3600 * timezone * 1000;
const dateInitial = new date (t);
const [datE, setDate] = useState (dateInitial);
useEffect (() => {
const interval = setInterval (() => {
const t = date.getTime () + (1 * 1000);
setDate (new date (t));
}, 1000);
return () => {
// ONLY clears the return of this function
// When the component is unmounted from the DOM
console.log ("Cleanup function (componentWillUnmount ())");
clearTimeout (interval); // The setTimeout is cleared as soon as the component is unmounted from the DOM
}
}, [date);
return (
<h2 style = {{display: show? true: 'none'}}> Today in {country} is {date.toLocaleDateString () + '' + date.toLocaleTimeString ()} </h2>
)
};
export default Clock;
功能组件使用挂钩到“日期”状态的 useEffect 属性。
函数:
() => {
const t = date.getTime () + (1 * 1000);
setDate (new date (t));
}, 1000);
作为第一个参数传递给useEffect,应该用于componentDidMount和componentDidUpdate生命周期事件。
同时清理函数:
return () => {
// ONLY clears the return of this function
// When the component is unmounted from the DOM
console.log ("Cleanup function (componentWillUnmount ())");
clearTimeout (interval); // The setTimeout is cleared as soon as the component is unmounted from the DOM
}
应该在组件生命周期的componentWillUnmount事件中执行。
但是如果我“运行”我们的组件,我会在日志中看到:
如您所见,componentWillUnmount 事件每秒发生一次。如果我没记错的话,当组件从 DOM 中移除时,不应该发生 componentWillUnmount 吗?在这种情况下,我们只有 DOM 的新呈现,而不是从 DOM 中删除元素。我很困惑。另一方面,如果您使用 class 组件尝试以下示例:
Clock with class component (on codepen.io)
你会看到 console.log ("componentWillUnmount");从未出现过...
我还观察到,如果我更改选项卡,我在 post 中插入的组件会丢失几秒钟,而在 codepen.io 中插入的组件不会丢失“节拍”。
对不起,我有点困惑。
我提前感谢你总是宝贵的澄清。
useEffect 代表 componentDidMount 和 componentWillUnmount 只有当你给它一个空的依赖数组时:
useEffect(() => {
//code that will only be executed when component mount
return () => {
//code that will only executed when component unmount
}
}, [])
在你的例子中,你在依赖数组中有日期,这意味着,每次日期改变,一个新的执行,把它想象成 useEffect 是一个迷你组件,它的生命取决于日期值 -时间日期更改它卸载并重新安装。
在这种情况下我们需要 return 函数的原因是,例如当我们有一个依赖于日期值的侦听器时,所以每次我们需要删除日期更改使用旧值的旧侦听器并使用新值附加新侦听器。
useEffect(() => {
//We attach a listener which depends on date value
const listenerHandler = () => {console.log(date)}
window.addEventListener('event', listenerHandler)
return () => {
//We need to remove the listener with old value so we don't have many listeners attached each time date changes
window.removeEventListener('event', listenerHandler)
}
}, [date])