Search code examples
reactjsreact-hooksuse-effect

why does useEffect() not work in this simple counter example?


here is my code:

import { useState, useEffect } from 'react';
export default function CompA() {
  const [counter, setCounter] = useState(0);

  const increment = () => {
    setCounter(counter + 1);
  };

  const isEven = useEffect(() => {
    return counter % 2 === 0;
  }, [counter]);
  return (
    <div>
      <button onClick={increment}> Counter {counter}</button>
      <h2>{isEven ? 'Even' : 'Odd'}</h2>
    </div>
  );
}

Based on my limited knowledge useEffect hook with a dependency, runs several times. first in the initial render, and then when the counter state in the dependency array changes. With every change in the state value, useEffect rerender the whole component so we can see the changes visually.

In this simple example, in the initial render the useEffect should return a True or False, and then based on this value, the ternary operator in h2 tag should show the value accordingly.

The issue is that when I run my code, the h2 tag is still equal to ODD, even though my initial counter state is 0. Plus, pressing the button will change the value of the counter, and the useEffect should execute and trigger a re-rendering.

However, none of these work! why is that? Am I doing something wrong?


Solution

  • useEffect doesn't return anything, and it's not useful for what you're trying to do. Since useEffect doesn't return anything, isEven is undefined, which results in displaying "Odd".

    I would simply write an inline calculation like this:

    const isEven = counter % 2 === 0;
    

    useEffect isn't needed to cause the component to render, that's what calling setCounter is for. When the component rerenders, this line will calculate isEven based on the latest value of counter. If the calculation was a very expensive one (it's not) and you wanted to improve performance by skipping the calculation if nothing had changed, you could use useMemo:

    const isEven = useMemo(() => {
      return counter % 2 === 0;
    }, [counter])
    

    Again though, that's not necessary for a calculation as lightweight as the one you're doing.