从子到父的数据流反应

时间:2019-09-06 16:47:01

标签: reactjs components

我正在设置一个计时器,我试图使子组件“ Timer”与父组件“ App”进行通信,以便父组件可以更改计时器(一个用于锻炼时间,另一个用于休息时间。时间);但无法正常运行,则该应用会启动,但不会更改计时器。 我是编码和StackOverflow的新手,所以我希望任何人在此问题上有任何指导和建议。

我正在尝试使用useEffect钩子将计时器达到“ 0”值时将状态“更改”设置为“真”。然后我想在“ change”为“ true”时调用一个函数,该函数从需要将状态从“ ExerciseTime”更改为“!ExerciseTime”的父“ App”调用上述函数。显然到目前为止还没有工作...

这是父组件(我将其简化为仅存在实际问题的部分):

function App() {
  const [exerciseTime, setExerciseTime] = useState(true);

  const handleTimer = () => {
    setExerciseTime(!exerciseTime);
  };


  return (
      </div>
      {exerciseTime ? <Timer time={5} change ={handleTimer()} /> : <Timer 
 time={3} change ={handleTimer} />}
       <div>
   );
 }

这是子组件:

const Timer = props => {
 const [seconds, setSeconds] = useState(props.time);
 const [isActive, setIsActive] = useState(false);
 const [change, setChange] = useState(false);

const toggle = () => {
  setIsActive(!isActive);
};

if (change) {
  props.change();
}

useEffect(() => {
 let interval = null;
  function changing() {
   setChange(!change);
 }

if (isActive && seconds !== 0) {
  interval = setInterval(() => {
    setSeconds(seconds => seconds - 1);
   }, 1000);
} else if (!isActive && seconds !== 0) {
   clearInterval(interval);
} else if (seconds === 0) {
   changing();
   clearInterval(interval)
}
return () => clearInterval(interval);
}, [isActive, seconds, change]);

return (
  <div className="timer">
    <div className="timer-seconds">{seconds}</div>
    <div className="config-button">
      <button
        className={`button button-${isActive ? "active" : "inactive"}`}
        onClick={toggle}
      >
        {isActive ? "Pause" : "Start"}
      </button>
    </div>
  </div>
 );
};

我希望计时器在到达“ 0”值时更改为新的计时器,依此类推...

2 个答案:

答案 0 :(得分:1)

首先:您需要使用引用-handleTimer而不是调用函数handleTimer()

第二:您做的方式是开始太多的时间间隔。这会破坏您的应用程序。

第三:即使时间道具发生变化,计时器组件也不会卸载,因此一旦计时器结束,该值将为0而不是3或5。

有更好的方法可以执行此操作,但是我不想离开您正在做的事情,因此请对其进行修改以使其起作用。

const Timer = props => {
  const [seconds, setSeconds] = React.useState(props.time);
  const [isActive, setIsActive] = React.useState(false);
  const toggle = () => {
    setIsActive(!isActive);
  };

  React.useEffect(
    () => {
      let interval;
      if (isActive && seconds !== 0) {
        interval = setInterval(
          () => setSeconds(seconds => seconds - 1), 1000
        );
      }
      if (isActive && seconds === 0) {
        setIsActive(false)
        props.change()
      }
      return () => {
        clearInterval(interval)
      }

    }, [isActive, seconds]);

  return (
    <div className="timer">
      <div className="timer-seconds">{seconds}</div>
      <div className="config-button">
        <button
          className={`button button-${isActive ? "active" : "inactive"}`}
          onClick={toggle}
        >
          {isActive ? "Pause" : "Start"}
        </button>
      </div>
    </div>
  );
};

function App() {
  const [exerciseTime, setExerciseTime] = React.useState(true);

  const handleTimer = () => {
    setExerciseTime((exTime) => !exTime);
  };

  return (
    <div key={exerciseTime}>
      {exerciseTime ? <Timer time={5} change={handleTimer} /> : <Timer
        time={3} change={handleTimer} />
      }
    </div>
  );
}

export default App 

编辑:

https://codesandbox.io/embed/trusting-lumiere-d7df7

答案 1 :(得分:0)

您想将函数而不是函数的返回值传递给变更处理程序:

{exerciseTime ? <Timer time={5} change ={handleTimer} /> : <Timer time={3} change ={handleTimer} />}

基本上handleTimer()应该变成handleTimer