title: converting a react app from classes to hooks
body: <p>I have this Pomodoro react app written in classes, and I would like to convert to hooks.</p>
  <pre><code>import React from 'react';
  import SetTimer from './components/SetTimer';
  import './App.css';
  
  class App extends React.Component {
    state = {
      breakCount: 5,
      sessionCount: 25,
      clockCount: 25 * 60,
      currentTimer: 'Session',
      isPlaying: false,
    };
  
    constructor(props) {
      super(props);
      this.loop = undefined;
      this.handlePlayPause = this.handlePlayPause.bind(this);
    }
  
    componentWillUnmount() {
      clearInterval(this.loop);
    }
  
    handlePlayPause() {
      const { isPlaying } = this.state;
      console.log(isPlaying);
      if (isPlaying) {
        //if the time is playing and we press this button, then we need to puase or clear the playing intervals
        clearInterval(this.loop);
        this.setState({ isPlaying: false });
      } else {
        this.setState({ isPlaying: true });
        this.loop = setInterval(() =&gt; {
          const {
            clockCount,
            breakCount,
            sessionCount,
            currentTimer,
          } = this.state;
          if (clockCount === 0) {
            this.setState({
              currentTimer: currentTimer === 'Session' ? 'Break' : 'Session',
              clockCount:
                currentTimer === 'Session' ? breakCount * 60 : sessionCount * 60,
            });
          } else {
            this.setState({ clockCount: clockCount - 1 });
          }
        }, 1000);
      }
    }
    handleReset = () =&gt; {
      this.setState({
        breakCount: 5,
        sessionCount: 25,
        clockCount: 25 * 60,
        currentTimer: 'Session',
        isPlaying: false,
      });
      clearInterval(this.loop);
    };
  
    convertTime = (count) =&gt; {
      const minutes = Math.floor(count / 60);
      let seconds = count % 60;
      seconds = seconds &lt; 10 ? `0${seconds}` : `${seconds}`;
      return `${minutes}:${seconds}`;
    };
  
    handleBreakDecrease = () =&gt; {
      const { breakCount } = this.state;
      if (breakCount &gt;= 2) {
        this.setState({ breakCount: breakCount - 1 });
      }
    };
    handleBreakIncrease = () =&gt; {
      const { breakCount } = this.state;
      this.setState({ breakCount: breakCount + 1 });
    };
    handleSessionDecrease = () =&gt; {
      const { sessionCount } = this.state;
      if (sessionCount &gt;= 2) {
        this.setState({
          sessionCount: sessionCount - 1,
          clockCount: (sessionCount - 1) * 60,
        });
      }
    };
    handleSessionIncrease = () =&gt; {
      const { sessionCount } = this.state;
      this.setState({
        sessionCount: sessionCount + 1,
      });
    };
  
    render() {
      const { breakCount, sessionCount, clockCount, currentTimer } = this.state;
      const breakProps = {
        title: 'Break Length',
        count: breakCount,
        handleDecrease: this.handleBreakDecrease,
        handleIncrease: this.handleBreakIncrease,
      };
  
      const sessionProps = {
        title: 'Session Length',
        count: sessionCount,
        handleDecrease: this.handleSessionDecrease,
        handleIncrease: this.handleSessionIncrease,
      };
  
      return (
        &lt;div&gt;
          &lt;div className='flex'&gt;
            &lt;SetTimer {...breakProps} /&gt;
            &lt;SetTimer {...sessionProps} /&gt;
          &lt;/div&gt;
          &lt;div className='clock-container'&gt;
            &lt;h1&gt;{currentTimer}&lt;/h1&gt;
            &lt;span&gt;{this.convertTime(clockCount)}&lt;/span&gt;
            &lt;div className='flex'&gt;
              &lt;button onClick={this.handlePlayPause}&gt;
                {this.state.isPlaying ? (
                  &lt;i className={`fas fa-pause`}&gt;&lt;/i&gt;
                ) : (
                  &lt;i className='fas fa-play'&gt;&lt;/i&gt;
                )}
              &lt;/button&gt;
              &lt;button onClick={this.handleReset}&gt;
                &lt;i className='fas fa-sync-alt'&gt;&lt;/i&gt;
              &lt;/button&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      );
    }
  }
  
  export default App;
  
  </code></pre>
  <p>I did the following changes, and although everything seems to be working, one critical thing that isn't is the <code>setInterval</code> function inside the <code>handlePlayPause</code> function that runs only once. I wonder why!</p>
  <pre><code>import React, { useState, useEffect } from 'react';
  import SetTimer from './components/SetTimer';
  import './App.css';
  
  const App = () =&gt; {
    let loop = undefined;
  
    const [timeVariables, setTimeVariables] = useState({
      breakCount: 5,
      sessionCount: 25,
      clockCount: 25 * 60,
      currentTimer: 'Session',
      isPlaying: false,
    });
  
    const {
      breakCount,
      sessionCount,
      clockCount,
      currentTimer,
      isPlaying,
    } = timeVariables;
  
    useEffect(() =&gt; {
      return () =&gt; {
        clearInterval(loop);
      };
    }, []);
  
    const handlePlayPause = () =&gt; {
      const { isPlaying } = timeVariables;
      if (isPlaying) {
        clearInterval(loop);
        setTimeVariables({ ...timeVariables, isPlaying: false });
      } else {
        setTimeVariables({ ...timeVariables, isPlaying: true });
        loop = setInterval(() =&gt; {
          console.log('Hello');
          const {
            clockCount,
            breakCount,
            sessionCount,
            currentTimer,
          } = timeVariables;
          if (clockCount === 0) {
            setTimeVariables({
              ...timeVariables,
              currentTimer: currentTimer === 'Session' ? 'Break' : 'Session',
              clockCount:
                currentTimer === 'Session' ? breakCount * 60 : sessionCount * 60,
            });
          } else {
            setTimeVariables({ ...timeVariables, clockCount: clockCount - 1 });
          }
        }, 1000);
      }
    };
    const handleReset = () =&gt; {
      setTimeVariables({
        breakCount: 5,
        sessionCount: 25,
        clockCount: 25 * 60,
        currentTimer: 'Session',
        isPlaying: false,
      });
      clearInterval(loop);
    };
  
    const convertTime = (count) =&gt; {
      const minutes = Math.floor(count / 60);
      let seconds = count % 60;
      seconds = seconds &lt; 10 ? `0${seconds}` : `${seconds}`;
      return `${minutes}:${seconds}`;
    };
  
    const handleBreakDecrease = () =&gt; {
      const { breakCount } = timeVariables;
      if (breakCount &gt;= 2) {
        setTimeVariables({ ...timeVariables, breakCount: breakCount - 1 });
      }
    };
    const handleBreakIncrease = () =&gt; {
      const { breakCount } = timeVariables;
      setTimeVariables({ ...timeVariables, breakCount: breakCount + 1 });
    };
    const handleSessionDecrease = () =&gt; {
      const { sessionCount } = timeVariables;
      if (sessionCount &gt;= 2) {
        setTimeVariables({
          ...timeVariables,
          sessionCount: sessionCount - 1,
          clockCount: (sessionCount - 1) * 60,
        });
      }
    };
    const handleSessionIncrease = () =&gt; {
      const { sessionCount } = timeVariables;
      setTimeVariables({
        ...timeVariables,
        sessionCount: sessionCount + 1,
        clockCount: (sessionCount + 1) * 60,
      });
    };
  
    const breakProps = {
      title: 'Break Length',
      count: breakCount,
      handleDecrease: handleBreakDecrease,
      handleIncrease: handleBreakIncrease,
    };
  
    const sessionProps = {
      title: 'Session Length',
      count: sessionCount,
      handleDecrease: handleSessionDecrease,
      handleIncrease: handleSessionIncrease,
    };
  
    return (
      &lt;div&gt;
        &lt;div className='flex'&gt;
          &lt;SetTimer {...breakProps} /&gt;
          &lt;SetTimer {...sessionProps} /&gt;
        &lt;/div&gt;
        &lt;div className='clock-container'&gt;
          &lt;h1&gt;{currentTimer}&lt;/h1&gt;
          &lt;span&gt;{convertTime(clockCount)}&lt;/span&gt;
          &lt;div className='flex'&gt;
            &lt;button onClick={handlePlayPause}&gt;
              {isPlaying ? (
                &lt;i className={`fas fa-pause`}&gt;&lt;/i&gt;
              ) : (
                &lt;i className='fas fa-play'&gt;&lt;/i&gt;
              )}
            &lt;/button&gt;
            &lt;button onClick={handleReset}&gt;
              &lt;i className='fas fa-sync-alt'&gt;&lt;/i&gt;
            &lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    );
  };
  
  export default App;
  
  </code></pre>
  <p><strong>Update</strong>: with individual state variables</p>
  <pre><code>import React, { useState, useEffect } from 'react';
  import SetTimer from './components/SetTimer';
  import './App.css';
  
  const App = () =&gt; {
    console.log('rendered');
    let loop = undefined;
    // const [loop, setLoop] = useState(undefined);
    const [breakCount, setBreakCount] = useState(5);
    const [sessionCount, setSessionCount] = useState(25);
    const [clockCount, setClockCount] = useState(25 * 60);
    const [currentTimer, setCurrentTimer] = useState('Session');
    const [isPlaying, setIsPlaying] = useState(false);
  
    // const [timeVariables, setTimeVariables] = useState({
    //   breakCount: 5,
    //   sessionCount: 25,
    //   clockCount: 25 * 60,
    //   currentTimer: 'Session',
    //   isPlaying: false,
    // });
  
    // const {
    //   breakCount,
    //   sessionCount,
    //   clockCount,
    //   currentTimer,
    //   isPlaying,
    // } = timeVariables;
  
    // useEffect(() =&gt; {
    //   // setClockCount(
    //   //   currentTimer === 'Session' ? sessionCount * 60 : breakCount * 60
    //   // );
    //   return () =&gt; {
    //     clearInterval(loop);
    //   };
    // }, []);
  
    const handlePlayPause = () =&gt; {
      // const { isPlaying } = timeVariables;
      if (isPlaying) {
        console.log(loop, isPlaying);
        clearInterval(loop);
        setIsPlaying(false);
      } else {
        loop = setInterval(() =&gt; {
          console.log(loop, isPlaying);
          setIsPlaying(true);
          // const {
          //   clockCount,
          //   breakCount,
          //   sessionCount,
          //   currentTimer,
          // } = timeVariables;
          if (clockCount === 0) {
            setCurrentTimer(currentTimer === 'Session' ? 'Break' : 'Session');
            setClockCount(
              currentTimer === 'Session' ? breakCount * 60 : sessionCount * 60
            );
            // setTimeVariables({
            //   ...timeVariables,
            //   currentTimer: currentTimer === 'Session' ? 'Break' : 'Session',
            //   clockCount:
            //     currentTimer === 'Session' ? breakCount * 60 : sessionCount * 60,
            // });
          } else {
            setClockCount((clockCount) =&gt; clockCount - 1);
            // setTimeVariables({ ...timeVariables, clockCount: clockCount - 1 });
          }
        }, 1000);
      }
    };
    const handleReset = () =&gt; {
      setBreakCount(5);
      setSessionCount(25);
      setClockCount(25 * 60);
      setCurrentTimer('Session');
      setIsPlaying(false);
      // setTimeVariables({
      //   breakCount: 5,
      //   sessionCount: 25,
      //   clockCount: 25 * 60,
      //   currentTimer: 'Session',
      //   isPlaying: false,
      // });
      clearInterval(loop);
    };
  
    const convertTime = (count) =&gt; {
      const minutes = Math.floor(count / 60);
      let seconds = count % 60;
      seconds = seconds &lt; 10 ? `0${seconds}` : `${seconds}`;
      return `${minutes}:${seconds}`;
    };
  
    const handleBreakDecrease = () =&gt; {
      // const { breakCount } = timeVariables;
      if (breakCount &gt;= 2) {
        setBreakCount(breakCount - 1);
        // setTimeVariables({ ...timeVariables, breakCount: breakCount - 1 });
      }
    };
    const handleBreakIncrease = () =&gt; {
      // const { breakCount } = timeVariables;
      setBreakCount(breakCount + 1);
      // setTimeVariables({ ...timeVariables, breakCount: breakCount + 1 });
    };
    const handleSessionDecrease = () =&gt; {
      // const { sessionCount } = timeVariables;
      if (sessionCount &gt;= 2) {
        setSessionCount(sessionCount - 1);
        setClockCount((sessionCount - 1) * 60);
        // setTimeVariables({
        //   ...timeVariables,
        //   sessionCount: sessionCount - 1,
        //   clockCount: (sessionCount - 1) * 60,
        // });
      }
    };
    const handleSessionIncrease = () =&gt; {
      setSessionCount(sessionCount + 1);
      setClockCount((sessionCount + 1) * 60);
      // const { sessionCount } = timeVariables;
      // setTimeVariables({
      //   ...timeVariables,
      //   sessionCount: sessionCount + 1,
      //   clockCount: (sessionCount + 1) * 60,
      // });
    };
  
    const breakProps = {
      title: 'Break Length',
      count: breakCount,
      handleDecrease: handleBreakDecrease,
      handleIncrease: handleBreakIncrease,
    };
  
    const sessionProps = {
      title: 'Session Length',
      count: sessionCount,
      handleDecrease: handleSessionDecrease,
      handleIncrease: handleSessionIncrease,
    };
  
    return (
      &lt;div&gt;
        &lt;div className='flex'&gt;
          &lt;SetTimer {...breakProps} /&gt;
          &lt;SetTimer {...sessionProps} /&gt;
        &lt;/div&gt;
        &lt;div className='clock-container'&gt;
          &lt;h1&gt;{currentTimer}&lt;/h1&gt;
          &lt;span&gt;{convertTime(clockCount)}&lt;/span&gt;
          &lt;div className='flex'&gt;
            &lt;button onClick={handlePlayPause}&gt;
              {isPlaying ? (
                &lt;i className={`fas fa-pause`}&gt;&lt;/i&gt;
              ) : (
                &lt;i className='fas fa-play'&gt;&lt;/i&gt;
              )}
            &lt;/button&gt;
            &lt;button onClick={handleReset}&gt;
              &lt;i className='fas fa-sync-alt'&gt;&lt;/i&gt;
            &lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    );
  };
  
  export default App;
  
  </code></pre>