如果我们想限制useEffect
仅在组件安装时才运行,则可以在useEffect
上添加[]
的第二个参数。
useEffect(() => {
// ...
}, []);
但是如何使useEffect
仅在组件被更新的那一刻(初始安装除外)才能运行?
答案 0 :(得分:13)
如果您要运行useEffect仅在除初始安装以外的更新上运行,则可以使用useRef
来跟踪带有useEffect
的initialMount,而无需第二个参数。
const isInitialMount = useRef(true);
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
// Your useEffect code here to be run on update
}
});
答案 1 :(得分:6)
我真的很喜欢Shubham的回复,所以我把它做成了自定义的挂钩
/**
* A custom useEffect hook that only triggers on updates, not on initial mount
* Idea stolen from: https://stackoverflow.com/a/55075818/1526448
* @param {Function} effect
* @param {Array<any>} dependencies
*/
export default function useUpdateEffect(effect, dependencies = []) {
const isInitialMount = useRef(true);
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
effect();
}
}, dependencies);
}
答案 2 :(得分:2)
您可以通过将状态设置为非布尔初始值(例如空值)来解决此问题:
const [isCartOpen,setCartOpen] = useState(null);
const [checkout,setCheckout] = useState({});
useEffect(() => {
// check to see if its the initial state
if( isCartOpen === null ){
// first load, set cart to real initial state, after load
setCartOpen( false );
}else if(isCartOpen === false){
// normal on update callback logic
setCartOpen( true );
}
}, [checkout]);
答案 3 :(得分:1)
Shubham和Mario都提出了正确的方法,但是代码仍然不完整,没有考虑以下情况。
effect
函数可能会从中返回一个清理函数,该函数永远不会被调用将更完整的代码分享到下面,该代码涵盖了上面两个遗漏的情况:
import React from 'react';
const useIsMounted = function useIsMounted() {
const isMounted = React.useRef(false);
React.useEffect(function setIsMounted() {
isMounted.current = true;
return function cleanupSetIsMounted() {
isMounted.current = false;
};
}, []);
return isMounted;
};
const useUpdateEffect = function useUpdateEffect(effect, dependencies) {
const isMounted = useIsMounted();
const isInitialMount = React.useRef(true);
React.useEffect(() => {
let effectCleanupFunc = function noop() {};
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
effectCleanupFunc = effect() || effectCleanupFunc;
}
return () => {
effectCleanupFunc();
if (!isMounted.current) {
isInitialMount.current = true;
}
};
}, dependencies); // eslint-disable-line react-hooks/exhaustive-deps
};
答案 4 :(得分:0)
从Subham的答案中寻求帮助此代码仅在特定项目更新上运行,而不是在每次更新时都运行,而不是在组件初始安装时运行。
const isInitialMount = useRef(true); //useEffect to run only on updates except initial mount
//useEffect to run only on updates except initial mount
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
if(fromScreen!='ht1' && appStatus && timeStamp){
// let timeSpentBG = moment().diff(timeStamp, "seconds");
// let newHeatingTimer = ((bottomTab1Timer > timeSpentBG) ? (bottomTab1Timer - timeSpentBG) : 0);
// dispatch({
// type: types.FT_BOTTOM_TAB_1,
// payload: newHeatingTimer,
// })
// console.log('Appstaatus', appStatus, timeSpentBG, newHeatingTimer)
}
}
}, [appStatus])
答案 5 :(得分:0)
const [mounted, setMounted] = useRef(false)
useEffect(() => {
if(!mounted) return setMounted(true)
// your update codes goes here
});
答案 6 :(得分:0)
使用useEffect
的 Cleanup函数,而不使用空数组作为第二个参数:
useEffect(() => {
return () => {
// your code to be run only on update
}
});
如果愿意,可以使用另一个useEffect(将空数组作为第二个参数)进行初始安装,将代码照常放置在其主要功能中。
答案 7 :(得分:-1)
另一种方法是根据关注的程度两次调用useEffect。 请从博客文章下方的注释中查看RudyNappée的回答:
https://dev.to/savagepixie/how-to-mimic-componentdidupdate-with-react-hooks-3j8c
简而言之:
useEffect(concern1, [...]);
useEffect(concern2, [...]);
...
对于useEffect的每个实例,传递一个您尝试监视的不同数组参数。