Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

124
Visualizações
missing dependency warning when working with event listeners and states inside useEffect

Everytime I work with addEventListener(), and also want to access some state inside useEffect, I get the same issue. I can't add the state as dependency, because then I would create multiple event listeners each time the state changes. I almost everytime find myself stuck with the "React Hook useEffect has a missing dependency" warning. Let's say I have a component that needs to change it state on window.onClick() and on window.onDoubleClick(). If the state is true, click should change it to false, and if the state is false, double click should change it to true. So here's what I whould write:

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

export default function someComponent() {
  const [toggle, setToggle] = useState(false);

  useEffect(() => {
    window.addEventListener('click', (event) => {
      if (toggle) setToggle(false)
    })

    window.addEventListener('dblclick', (event) => {
      if (!toggle) setToggle(true)
    })
  }, [])

  return (
    <p>The toggle state is {toggle.toString()}</p>
  );
}

This code works, but I get the missing dependency warning. I can't add toggle to the dependency array, because then it will add another event listener each time the toggle state changes.

What am I doing wrong here? how should I fix this?

Edit: Maybe this example wasn't too good, but it's the simplest I could think of. But, this issue is also for when I create other event listeners, that have to be on the windows object, like scroll. I know I can use return to remove the event listener everytime, but for events like scroll it makes it much slower. It doesn't make sense to me that I have to remove and add it everytime, when I just don't need it to fire again.

about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

With react you don't have to use the window element in this case. Not even a useEffect.

By using the useEffect hook you are telling react to do something after render (depending on the dependency array). In this case changing state is not necessary immediately after rendering the page, only when the user interacts with the element.

Adding click events through the useEffect is probably not needed most of the time and and doing it like the example below will probably save you time and a headache and maybe even performance (correct me if i'm wrong).

I would personally do it like this.

import React, { useState } from 'react';
        
export default function someComponent() {
  const [toggle, setToggle] = useState(false);

  return (
    <p 
      onClick={() => setToggle(false)} 
      onDoubleClick={() => setToggle(true)}
    >
      The toggle state is {toggle.toString()}
    </p>
  );
}

You could also call functions from the element like so

  const [toggle, setToggle] = useState(false);

  const handleClick = () => {
    if (toggle) {
      setToggle(false);
    }
  };

  const handleDoubleClick = () => {
    if (!toggle) {
      setToggle(true);
    }
  };

  return (
    <p 
      onClick={() => handleClick()} 
      onDoubleClick={() => handleDoubleClick()}
    >
      The toggle state is {toggle.toString()}
    </p>
  );

CodeSandbox example

Edit staging-water-cuwo4

about 4 years ago · Juan Pablo Isaza Relatório

0

You can add a clean-up function to the useEffect hook to remove old listeners. This way you can pass toggle into the dependency array and you won't have stacking event listeners.

https://reactjs.org/docs/hooks-effect.html

  useEffect(() => {
    const handleClick = () => toggle ? setToggle(false) : setToggle(true);

    window.addEventListener('click', handleClick);
    window.addEventListener('dblclick', handleClick);

    return () => {
      window.removeEventListener('click', handleClick);
      window.removeEventListener('dblclick', handleClick);
    }
  }, [toggle]);

about 4 years ago · Juan Pablo Isaza Relatório

0

I can't add the state as dependency, because then I would create multiple event listeners each time the state changes.

There is a way around this, and that is to return a cleanup function from the useEffect callback. I would encourage you to read the linked section of the docs, then the below solution would become much clearer:

useEffect(() => {
  const handleClick = () => {
    setToggle(!toggle)
  }

  window.addEventListener('click', handleClick)    

  return () => {
    window.removeEventListener('click', handleClick)
  }
}, [toggle])

with the above solution, each time toggle is updated, the cleanup function is called, which removes the current event listener before running the effect again.

Also note that you can provide a callback function to setToggle, which receives the current value of toggle and returns the new value. With this approach you wouldn't need to pass toggle as a dependency to useEffect:

useEffect(() => {
  const handleClick = () => {
    setToggle(currentValue => !currentValue)
  }
  
  window.addEventListener("click", handleClick)

  return () => {
    window.removeEventListener("click", handleClick)
  }
}, [])
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda