Porque muitas vezes ao colocar uma variável no Array de dependências do useEffect ocorre o Loop Infinito e como resolver?
O problema ocorre quando um valor no array de dependência é alterado durante a renderização do componente e causa uma nova renderização, que pode ser desnecessária. Isso pode levar a um loop infinito de renderizações.
Para resolver esse problema, podemos usar o useRef
para armazenar uma referência a um valor que precisa ser usado dentro do useEffect
, mas que não deve ser incluído no array de dependência.
Por exemplo, suponha que temos um componente que precisa buscar dados de uma API sempre que um botão é clicado. Usando useEffect
para isso, poderíamos escrever algo como:
function MyComponent() { const [data, setData] = useState(null); const [buttonClicked, setButtonClicked] = useState(false); useEffect(() => { if (buttonClicked) { fetchData(); } }, [buttonClicked]); const fetchData = async () => { const response = await fetch('https://my-api.com/data'); const data = await response.json(); setData(data); } return ( <div> <button onClick={() => setButtonClicked(true)}>Fetch Data</button> {data && <p>{data}</p>} </div> ) }
Nesse exemplo, o useEffect
é executado toda vez que o buttonClicked
é alterado, o que faz com que a API seja chamada sempre que o botão é clicado. No entanto, se tivermos outros estados que afetam a renderização do componente, como um estado de filtro que não afeta a chamada da API, incluí-lo no array de dependência pode causar uma nova renderização desnecessária.
Nesse caso, podemos usar o useRef
para armazenar uma referência a um valor que precisa ser usado dentro do useEffect
, mas que não deve ser incluído no array de dependência. Podemos fazer isso adicionando uma referência buttonClickedRef
usando o useRef
, que não afeta a renderização do componente e garantir que ela seja sempre a mesma:
function MyComponent() { const [data, setData] = useState(null); const [buttonClicked, setButtonClicked] = useState(false); const buttonClickedRef = useRef(false); useEffect(() => { if (buttonClickedRef.current) { fetchData(); } }, [buttonClickedRef]); const fetchData = async () => { const response = await fetch('https://my-api.com/data'); const data = await response.json(); setData(data); } return ( <div> <button onClick={() => { setButtonClicked(true); buttonClickedRef.current = true; }}>Fetch Data</button> {data && <p>{data}</p>} </div> ) }
Aqui, ao clicar no botão, estamos atualizando o estado do buttonClicked
como antes e também atualizando o buttonClickedRef.current
para true
. Como a referência não afeta a renderização do componente, não precisamos incluí-la no array de dependência do useEffect
, e podemos usá-la para garantir que a chamada da API ocorra apenas quando o botão for clicado.
Uma outra forma de se resolver esta dor, mas lembre-se vai depender da forma como seu código estiver disposto
Uma outra forma de resolver o problema do useEffect
que depende de um valor que não deve estar no array de dependência é usando uma função de atualização de estado em vez do valor diretamente.
Em vez de incluir o valor no array de dependência, podemos incluir a função de atualização de estado que altera o valor. Dessa forma, o useEffect
sempre usará a versão mais recente da função, que sempre atualiza o valor correto.
Por exemplo, usando o mesmo exemplo anterior, podemos modificar o buttonClicked
para ser um objeto com uma propriedade value
, e usar uma função de atualização de estado para atualizá-lo. Isso nos permite incluir apenas a função setButtonClicked
no array de dependência do useEffect
:
function MyComponent() { const [data, setData] = useState(null); const [buttonClicked, setButtonClicked] = useState({ value: false }); useEffect(() => { if (buttonClicked.value) { fetchData(); } }, [setButtonClicked]); const fetchData = async () => { const response = await fetch('https://my-api.com/data'); const data = await response.json(); setData(data); } return ( <div> <button onClick={() => setButtonClicked({ value: true })}>Fetch Data</button> {data && <p>{data}</p>} </div> ) }
Nesse exemplo, usamos uma função de atualização de estado em setButtonClicked
para atualizar o valor de buttonClicked
. Dessa forma, podemos incluir apenas a função setButtonClicked
no array de dependência do useEffect
. O valor real de buttonClicked
é atualizado automaticamente pelo React sempre que a função setButtonClicked
é chamada, garantindo que o useEffect
sempre use o valor mais recente e atualizado.
Essa abordagem também pode ser útil em outros casos em que precisamos atualizar um estado com base em seu valor anterior, ou quando o estado é um objeto com várias propriedades e só queremos atualizar uma delas.