componentWillUnmount 与 React useEffect 挂钩
componentWillUnmount with React useEffect hook
如何使用 useEffect
挂钩(或与此相关的任何其他挂钩)来复制 componentWillUnmount
?
在传统的 class 组件中,我会做这样的事情:
class Effect extends React.PureComponent {
componentDidMount() { console.log("MOUNT", this.props); }
componentWillUnmount() { console.log("UNMOUNT", this.props); }
render() { return null; }
}
使用 useEffect
挂钩:
function Effect(props) {
React.useEffect(() => {
console.log("MOUNT", props);
return () => console.log("UNMOUNT", props)
}, []);
return null;
}
(完整示例:https://codesandbox.io/s/2oo7zqzx1n)
这是行不通的,因为 useEffect
中返回的 "cleanup" 函数会捕获挂载期间的道具,而不是卸载期间道具的状态。
如何在 useEffect
clean up 没有 运行 每次 prop 更改的函数体(或清理)中获得最新版本的道具?
类似的没有解决访问最新道具的部分。
react docs状态:
If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run.
然而在这种情况下,我依赖道具...但仅用于清理部分...
您可以使用 useRef 并将要使用的道具存储在闭包中,例如 render useEffect return 回调方法
function Home(props) {
const val = React.useRef();
React.useEffect(
() => {
val.current = props;
},
[props]
);
React.useEffect(() => {
return () => {
console.log(props, val.current);
};
}, []);
return <div>Home</div>;
}
然而,更好的方法是将第二个参数传递给 useEffect
,以便在所需道具发生任何更改时进行清理和初始化
React.useEffect(() => {
return () => {
console.log(props.current);
};
}, [props.current]);
useLayoutEffect() 是你 2021 年的答案
useLayoutEffect(() => {
return () => {
// Your code here.
}
}, [])
这等同于 ComponentWillUnmount。
99% 的时间你想使用 useEffect,但如果你想在卸载之前执行任何操作 DOM 那么你可以使用我提供的代码。
useEffect(() => {
if (elements) {
const cardNumberElement =
elements.getElement('cardNumber') || // check if we already created an element
elements.create('cardNumber', defaultInputStyles); // create if we did not
cardNumberElement.mount('#numberInput');
}
}, [elements]);
useLayoutEffect
非常适合清理 DOM 节点上的 eventListeners。
否则,使用常规 useEffect
ref.current 将在挂钩触发时为空
有关 React 文档的更多信息 https://reactjs.org/docs/hooks-reference.html#uselayouteffect
import React, { useLayoutEffect, useRef } from 'react';
const audioRef = useRef(null);
useLayoutEffect(() => {
if (!audioRef.current) return;
const progressEvent = (e) => {
setProgress(audioRef.current.currentTime);
};
audioRef.current.addEventListener('timeupdate', progressEvent);
return () => {
try {
audioRef.current.removeEventListener('timeupdate', progressEvent);
} catch (e) {
console.warn('could not removeEventListener on timeupdate');
}
};
}, [audioRef.current]);
将 ref 附加到组件 DOM 节点
<audio ref={audioRef} />
如何使用 useEffect
挂钩(或与此相关的任何其他挂钩)来复制 componentWillUnmount
?
在传统的 class 组件中,我会做这样的事情:
class Effect extends React.PureComponent {
componentDidMount() { console.log("MOUNT", this.props); }
componentWillUnmount() { console.log("UNMOUNT", this.props); }
render() { return null; }
}
使用 useEffect
挂钩:
function Effect(props) {
React.useEffect(() => {
console.log("MOUNT", props);
return () => console.log("UNMOUNT", props)
}, []);
return null;
}
(完整示例:https://codesandbox.io/s/2oo7zqzx1n)
这是行不通的,因为 useEffect
中返回的 "cleanup" 函数会捕获挂载期间的道具,而不是卸载期间道具的状态。
如何在 useEffect
clean up 没有 运行 每次 prop 更改的函数体(或清理)中获得最新版本的道具?
类似的
react docs状态:
If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run.
然而在这种情况下,我依赖道具...但仅用于清理部分...
您可以使用 useRef 并将要使用的道具存储在闭包中,例如 render useEffect return 回调方法
function Home(props) {
const val = React.useRef();
React.useEffect(
() => {
val.current = props;
},
[props]
);
React.useEffect(() => {
return () => {
console.log(props, val.current);
};
}, []);
return <div>Home</div>;
}
然而,更好的方法是将第二个参数传递给 useEffect
,以便在所需道具发生任何更改时进行清理和初始化
React.useEffect(() => {
return () => {
console.log(props.current);
};
}, [props.current]);
useLayoutEffect() 是你 2021 年的答案
useLayoutEffect(() => {
return () => {
// Your code here.
}
}, [])
这等同于 ComponentWillUnmount。
99% 的时间你想使用 useEffect,但如果你想在卸载之前执行任何操作 DOM 那么你可以使用我提供的代码。
useEffect(() => {
if (elements) {
const cardNumberElement =
elements.getElement('cardNumber') || // check if we already created an element
elements.create('cardNumber', defaultInputStyles); // create if we did not
cardNumberElement.mount('#numberInput');
}
}, [elements]);
useLayoutEffect
非常适合清理 DOM 节点上的 eventListeners。
否则,使用常规 useEffect
ref.current 将在挂钩触发时为空
有关 React 文档的更多信息 https://reactjs.org/docs/hooks-reference.html#uselayouteffect
import React, { useLayoutEffect, useRef } from 'react';
const audioRef = useRef(null);
useLayoutEffect(() => {
if (!audioRef.current) return;
const progressEvent = (e) => {
setProgress(audioRef.current.currentTime);
};
audioRef.current.addEventListener('timeupdate', progressEvent);
return () => {
try {
audioRef.current.removeEventListener('timeupdate', progressEvent);
} catch (e) {
console.warn('could not removeEventListener on timeupdate');
}
};
}, [audioRef.current]);
将 ref 附加到组件 DOM 节点
<audio ref={audioRef} />