反应状态反复恢复到旧值
React state repeatedly reverts back to old value
有一个组件 "DateForm" 在提交表单时更改 "counterInfo" 的全局状态。
//DateForm component submittal function.
const submitDate = () =>{
props.setCounterInfo(dateInfo); //passes date info to be counterInfo state in App.js
props.setShowInputForm(false); //DateInfo component is no longer rendered
}
然后,在 app.js 中,counterInfo 状态被传递给 Timer 组件
const App = () => {
const [showInputForm, setShowInputForm] = useState(false);
const [counterInfo, setCounterInfo] = useState(undefined);
return (
<>
<Timer
counterInfo = {counterInfo}
></Timer>
{showInputForm &&
<DateForm
setShowInputForm = {setShowInputForm}
setCounterInfo = {setCounterInfo}
></DateForm>}
</>
);
}
Timer 函数内部有一个 useEffect 挂钩,它每隔一秒使用 counterInfo 的值。
//Inside the Timer Component
const [currTime, setCurrTime] = useState(null);
useEffect (() => {
setInterval(() => {
let timeLeft = (new Date(`${Months(props.counterInfo.year)[props.counterInfo.month-1].name} ${props.counterInfo.day} ${props.counterInfo.year} ${props.counterInfo.hour}:${props.counterInfo.minute}:${props.counterInfo.second}`).getTime()) - new Date().getTime();
setCurrTime(timeLeft);
},1000);
return(clearInterval());
}, [props, setCurrTime]);
我打算在 DateForm 中更新 counterInfo 的值时更新 Timer.js 中的 timeLeft 值,但是,当在 DateForm 中更改值时,新的结果在Timer.js中使用timeLeft的值时,counterInfo的值和旧值都会闪烁。此问题不是由 Timer.js 中的任何代码引起的,因为我尝试将 useEffect 挂钩移至 app.js 并将值传递给 Timer,但问题仍然存在。 setCounterInfo 状态唯一改变的地方是在 DateForm 组件中。
有人知道如何解决这个问题吗?
首先,您在 interval
decleration
处有一点语法错误
useEffect (() => {
let interval = setInterval(() => {...},1000);
return () => clearInterval(interval);
}, [props, setCurrTime]);
但不相关,React 默认情况下会在每次渲染后重新应用效果。这是有意的,有助于避免 React 组件中存在的全部 class 错误。
当谈到间隔时,如果每次调用 setInterval
时都应用渲染,它的具体问题是,它永远不会有机会实际 运行
换句话说,此代码可能会产生一些副作用,因为 useEffect
在每个 运行 中只关心当时的现有值而忘记其他所有内容,而 interval
是像这样。
为此,从我的角度来看,最佳做法是创建 useInterval
自定义挂钩,其中将同时存储回调
function useInterval(callback) {
const savedCallback = React.useRef();
useEffect(() => {
savedCallback.current = callback;
});
useEffect(() => {
function run() {
savedCallback.current();
}
let interval = setInterval(run ,1000);
return () => clearInterval(interval);
}, [])
}
//Inside the Timer Component
const [currTime, setCurrTime] = useState(null);
useInterval(()=>
setCurrTime((new Date(`${Months(props.counterInfo.year)[props.counterInfo.month-1].name} ${props.counterInfo.day} ${props.counterInfo.year} ${props.counterInfo.hour}:${props.counterInfo.minute}:${props.counterInfo.second}`).getTime()) - new Date().getTime()))
有一个组件 "DateForm" 在提交表单时更改 "counterInfo" 的全局状态。
//DateForm component submittal function.
const submitDate = () =>{
props.setCounterInfo(dateInfo); //passes date info to be counterInfo state in App.js
props.setShowInputForm(false); //DateInfo component is no longer rendered
}
然后,在 app.js 中,counterInfo 状态被传递给 Timer 组件
const App = () => {
const [showInputForm, setShowInputForm] = useState(false);
const [counterInfo, setCounterInfo] = useState(undefined);
return (
<>
<Timer
counterInfo = {counterInfo}
></Timer>
{showInputForm &&
<DateForm
setShowInputForm = {setShowInputForm}
setCounterInfo = {setCounterInfo}
></DateForm>}
</>
);
}
Timer 函数内部有一个 useEffect 挂钩,它每隔一秒使用 counterInfo 的值。
//Inside the Timer Component
const [currTime, setCurrTime] = useState(null);
useEffect (() => {
setInterval(() => {
let timeLeft = (new Date(`${Months(props.counterInfo.year)[props.counterInfo.month-1].name} ${props.counterInfo.day} ${props.counterInfo.year} ${props.counterInfo.hour}:${props.counterInfo.minute}:${props.counterInfo.second}`).getTime()) - new Date().getTime();
setCurrTime(timeLeft);
},1000);
return(clearInterval());
}, [props, setCurrTime]);
我打算在 DateForm 中更新 counterInfo 的值时更新 Timer.js 中的 timeLeft 值,但是,当在 DateForm 中更改值时,新的结果在Timer.js中使用timeLeft的值时,counterInfo的值和旧值都会闪烁。此问题不是由 Timer.js 中的任何代码引起的,因为我尝试将 useEffect 挂钩移至 app.js 并将值传递给 Timer,但问题仍然存在。 setCounterInfo 状态唯一改变的地方是在 DateForm 组件中。 有人知道如何解决这个问题吗?
首先,您在 interval
decleration
useEffect (() => {
let interval = setInterval(() => {...},1000);
return () => clearInterval(interval);
}, [props, setCurrTime]);
但不相关,React 默认情况下会在每次渲染后重新应用效果。这是有意的,有助于避免 React 组件中存在的全部 class 错误。
当谈到间隔时,如果每次调用 setInterval
时都应用渲染,它的具体问题是,它永远不会有机会实际 运行
换句话说,此代码可能会产生一些副作用,因为 useEffect
在每个 运行 中只关心当时的现有值而忘记其他所有内容,而 interval
是像这样。
为此,从我的角度来看,最佳做法是创建 useInterval
自定义挂钩,其中将同时存储回调
function useInterval(callback) {
const savedCallback = React.useRef();
useEffect(() => {
savedCallback.current = callback;
});
useEffect(() => {
function run() {
savedCallback.current();
}
let interval = setInterval(run ,1000);
return () => clearInterval(interval);
}, [])
}
//Inside the Timer Component
const [currTime, setCurrTime] = useState(null);
useInterval(()=>
setCurrTime((new Date(`${Months(props.counterInfo.year)[props.counterInfo.month-1].name} ${props.counterInfo.day} ${props.counterInfo.year} ${props.counterInfo.hour}:${props.counterInfo.minute}:${props.counterInfo.second}`).getTime()) - new Date().getTime()))