Home > Software design >  How to update variable passed into arrow function after component being rendered
How to update variable passed into arrow function after component being rendered

Time:10-26

I'm trying to build pomodoro clock (25 5).

I have an arrow function in the child component which takes two variabels: session (passed from parent, in seconds) and Boolean var. Problem is the function always stays at 1500 seconds even after i modified session in the parent component. It still passing the updated variable in the child but function always shows 25mins, cant find what am i doing wrong here.

The countdown itself works fine, i just need to figure out how to change amount of time passed in that function (called Countdown in the child component)

Child component:

import React, {useState, useEffect} from "react";

const Countdown = (Session, isStarted) => { // In this function Session is always 25 mins even after if i modify the state of the variable in the parent
    let InitialMinutes = Math.floor(Session / 60);
    let InitialSeconds = Session % 60;
    const [minutes, setMinutes ] = useState(InitialMinutes);
    const [seconds, setSeconds ] =  useState(InitialSeconds);
    
    useEffect(()=>{   
        if (isStarted) {
        let myInterval = setInterval(() => {
            if (seconds > 0) {
                setSeconds(seconds - 1);
            }
            if (seconds === 0) {
                if (minutes === 0) {
                    clearInterval(myInterval)
                } else {
                    setMinutes(minutes - 1);
                    setSeconds(59);
                }
            } 
        }, 1000)
        return ()=> {
            clearInterval(myInterval);
          };
    }}, [minutes, seconds, isStarted]);
    return (
        <div>
        { minutes === 0 && seconds === 0
            ? null
            : <h1> {minutes}:{seconds < 10 ?  `0${seconds}` : seconds}</h1> 
        }
        </div>
    )
}

function Timer({session}) {
    const [isStarted, setIsStarted] = React.useState(false);

    return (
    <div className='timer'>
        <h3>Session</h3>
        {Countdown(session, isStarted)}
        <button onClick={() => setIsStarted(true)}>start</button>
        <button>stop</button>
        <button>{session}</button>
    </div>
    )
}

export default Timer

Parent component:

function App() {
  const [Break, setBreak] = React.useState(5);
  const [Session, setSession] = React.useState(1500);

  const increaseBreak = () => {
    setBreak(prevBreak => prevBreak   1);
  };

  const decreaseBreak = () => {
    if (Break === 5) return Break
    setBreak(prevBreak => prevBreak - 1);
  };

  const increaseSession = () => {
    setSession(prevSession => prevSession   60);
    console.log(Session)
  }

  const decreaseSession = () => {
    return Session === 300? Session : setSession(prevSession => prevSession - 60);
  }

  const formatTime = time => {
    let minutes = Math.floor(time / 60);
    let seconds = time % 60;
    return (minutes < 10? `0${minutes}` : minutes)   ':'   (seconds < 10? `0${seconds}` : seconds)
  }

  return (
    <div className="App">
        <div className="wrapper">
          <div className='container'>
            <h1>25   5 Clock</h1>
            <div className='length'>
              <div className='break-length'>
                <h3>Break length</h3>
                <div className='adjust'>
                  <button onClick={decreaseBreak}>-</button>
                  <div className='number'>{Break}</div>
                  <button onClick={increaseBreak} > </button>
                </div>
              </div>
              <div className='session-length'>
                <h3>Session length</h3>
                <div className="adjust">
                  <button onClick={decreaseSession}>-</button>
                  <div className='number' id='session'>{formatTime(Session)}</div>
                  <button onClick={increaseSession}> </button>
                </div>
              </div>
            </div>
            <Timer session={Session}/>
          </div>
        </div>
    </div>
  );
}

export default App;

CodePudding user response:

The Countdown Component never watched for changes in the session state. I Added a use effect at the top of it and changed your variables to states. Code Below.

const Countdown = (Session, isStarted) => {
  console.log(Session);
  // In this function Session is always 25 mins even after if i modify the state of the variable in the parent
  const [InitialMinutes, setInialMinutes] = useState(Session / 60);
  const [InitialSeconds, setInitialSeconds] = useState(Session % 60);
  const [minutes, setMinutes] = useState(InitialMinutes);
  const [seconds, setSeconds] = useState(InitialSeconds);

  useEffect(() => {
    setInitialSeconds(Session % 60);
    setInialMinutes(Session / 60);
    setMinutes(InitialMinutes);
    setSeconds(InitialSeconds);
    console.log(minutes);
  }, [Session]);

  useEffect(() => {
    if (isStarted) {
      let myInterval = setInterval(() => {
        if (seconds > 0) {
          setSeconds(seconds - 1);
        }
        if (seconds === 0) {
          if (minutes === 0) {
            clearInterval(myInterval);
          } else {
            setMinutes(minutes - 1);
            setSeconds(59);
          }
        }
      }, 1000);
      return () => {
        clearInterval(myInterval);
      };
    }
  }, [minutes, seconds, isStarted]);

  return (
    <div>
      {minutes === 0 && seconds === 0 ? null : (
        <h1>
          {" "}
          {minutes}:{seconds < 10 ? `0${seconds}` : seconds}
        </h1>
      )}
    </div>
  );
};

function Timer({ session }) {
  const [isStarted, setIsStarted] = React.useState(false);

  return (
    <div className="timer">
      <h3>Session</h3>
      {Countdown(session, isStarted)}
      <button onClick={() => setIsStarted(true)}>start</button>
      <button>stop</button>
      <button>{session}</button>
    </div>
  );
}

export default Timer;
  • Related