Состояние реакции постоянно возвращается к старому значению - PullRequest
2 голосов
/ 08 мая 2020

Существует компонент «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
}

затем, в приложении. js состояние counterInfo передается таймеру component

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]);

Я намеревался сделать так, чтобы значение timeLeft в Timer. js обновлялось, когда значение counterInfo обновляется в DateForm, однако, когда значение изменяется в DateForm, результат как для нового значения counterInfo, так и для старого значения fla sh, когда значение timeLeft используется в Timer. js. Эта проблема не вызвана каким-либо кодом в Timer. js, потому что я попытался переместить обработчик useEffect в app. js и передать значение в Timer, но проблема не исчезла. Единственное место, где изменяется состояние setCounterInfo, - это компонент DateForm. Кто-нибудь знает, как это исправить?

1 Ответ

1 голос
/ 08 мая 2020

Во-первых, у вас битовый неправильный синтаксис при interval decleration


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

Но не связано, React по умолчанию повторно применяет эффекты после каждого рендеринга. Это сделано намеренно и помогает избежать целого класса ошибок, которые присутствуют в компонентах React.

Когда дело доходит до интервалов, его специфические вопросы вызывают, если рендеринг применялся каждый раз, когда вызывается setInterval, он никогда не будет получить шанс на самом деле запустить

Другими словами, этот код может иметь некоторые побочные эффекты, так как useEffect при каждом запуске заботится только о существующих значениях за это время и забывает все остальное, а interval isn ' t вот так.

Для этого, с моей точки зрения, лучше всего создать 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()))
...