【问题标题】:React state repeatedly reverts back to old value反应状态反复恢复到旧值
【发布时间】:2020-08-23 13:29:44
【问题描述】:

有一个组件“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 中更改值时,counterInfo 的新值和当在 Timer.js 中使用 timeLeft 的值时,旧的都会闪烁。这个问题不是由 Timer.js 中的任何代码引起的,因为我尝试将 useEffect 挂钩移动到 app.js 并将值传递给 Timer,但问题仍然存在。唯一改变 setCounterInfo 状态的地方是 DateForm 组件。 有谁知道如何解决这个问题?

【问题讨论】:

  • 不使用null作为初始状态值,不能从props中获取吗?

标签: javascript reactjs state setinterval


【解决方案1】:

首先,interval decleration 的语法有点错误


  useEffect (() => {
       let interval = setInterval(() => {...},1000);
       return () => clearInterval(interval);
   }, [props, setCurrTime]);

但不相关,React 默认在每次渲染后重新应用效果。这是有意为之,有助于避免 React 组件中存在的一整类错误。

说到间隔,它的特殊问题是如果每次调用 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()))

【讨论】:

    猜你喜欢
    • 2020-12-30
    • 1970-01-01
    • 2020-09-28
    • 2018-11-13
    • 2020-11-15
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    相关资源
    最近更新 更多