0

Why is useEffect() looping endlessly when the second set of arguments is being passed in []? The goal here is to get the state of the last record of props.state.hours.clockedIn on-load only (just once), and then store that boolean value to be used elsewhere. If the second argument does not have props.hours and clocked then useEffect does not get the value of the last record and is always false (when it should be true in this particular case). If they are passed in, I can see in the console.log the .map function is working as intended. Does useEffect() need to be used here? Is there another method to achieve getting just that last record's clockedIn value on-load?

const Hours = (props) => {
    const [clocked, setClocked] = useState(false);
    
    useEffect(() => {
        props.fetchHours()
            .then(() => {
                _.map(props.state.hours, (hour) => {
                    setClocked(hour.clockedIn)
                    console.log(clocked)
                })
            })
    }, [props, clocked])

    return (
        <div></div>
    );
};
ckingchris
  • 559
  • 1
  • 12
  • 25
  • 1
    Because you're modifying `clocked` within `useEffect` thus triggering state update, thus re-render, thus another round of `useEffect` – Yevhen Horbunkov Jul 07 '20 at 14:27
  • @ckingchris You have `clocked` as the dependency in your `useEffect` and inside useEffect you are changing the `clocked` variable which would result in an infinite loop. You should probably remove clocked as the dependency – rishabh0211 Jul 07 '20 at 14:27
  • Does this answer your question? [React hook useEffect runs continuously forever/infinite loop](https://stackoverflow.com/questions/53243203/react-hook-useeffect-runs-continuously-forever-infinite-loop) – Harmandeep Singh Kalsi Jul 07 '20 at 14:28
  • Try removing `console.log(clocked)` as well as from the dependency array – vahdet Jul 07 '20 at 14:28

2 Answers2

0

You use setClocked so you change the value of clocked. Also you have clocked inside the depedency array of useEffect thats why you have an endless loop.

If you want your useEffect to run only the first time that the component is rendered you need an empty depedency array

const Hours = (props) => {

const [clocked, setClocked] = useState(false);

useEffect(() => {
    props.fetchHours()
        .then(() => {
            _.map(props.state.hours, (hour) => {
                setClocked(hour.clockedIn)
                console.log(clocked)
            })
        })
}, [])

return (
    <div></div>
);

};

  • if the second argument is not passed in, the initial state loads as `false`, when the last record has a state of `true` in this particular case – ckingchris Jul 07 '20 at 14:58
0

If you need to use useEffect() hook to run some code on load just once after the initial render, the second argument must be an empty array like:

useEffect(() => {
  props.fetchHours()
      .then(() => {
          _.map(props.state.hours, (hour) => {
              setClocked(hour.clockedIn)
              console.log(clocked)
          })
      })
}, [])
Olga
  • 217
  • 1
  • 8
  • if the second argument is not passed in, the initial state loads as `false`, when the last record has a state of `true` in this particular case – ckingchris Jul 07 '20 at 14:37