Omar Omeiri
Omar Omeiri

Reputation: 1833

Weird behavior of React UseEffect with window click eventListener

I'm trying to implement a simple window Click counter. It needs to count clicks on the entire page, not in a single element with like <div onClick={() => handleClick()}></div>.

I have tried many variations of this code:

import React, { useState, useEffect } from 'react';
import $ from 'jquery';

function Test() {
  const [clicks, setClicks] = useState(0);

  function handleClick() {
    try {
      setClicks(() => clicks + 1);
    } catch (err) {
      console.error(err);
    }
  }

  useEffect(() => {
    console.log(clicks);
  }, [clicks]);

  useEffect(() => {
    $(window).on('click', handleClick);
    return () => {
      $(window).off('click', handleClick);
    };
  }, []);

  return (<div>{clicks}</div>);
}

export default Test;

The first useEffect just logs the click state variable every time it changes, so I can see what is happening. The second one adds the event listener and removes it on component unmount. The problem is that it works just fine for the first click. The first useEffect logs 1 and the value inside the <div> changes to 1. But nothing else happens if I keep clicking. Is this approach wrong?

Thanks!

Upvotes: 1

Views: 388

Answers (1)

Giorgi Moniava
Giorgi Moniava

Reputation: 28684

You have a classical stale closure problem. Use this instead:

  setClicks((clicks) => clicks+ 1);

The way you had it, your clicks would always refer to the value from the first render; it never got updated because you run your useEffect only once.

Upvotes: 2

Related Questions