Home > Software design >  useEffect dependency cause an infinite loop
useEffect dependency cause an infinite loop

Time:11-01

function Reply({ id, user }) {
  const [data, setData] = useState([]);
  const [replyText, setReplyText] = useState("");
  
  useEffect(() => {
    async function fetchData() {
      const response = await _axios.get("/reply/"   id);
      setData(response.data);
    }
    fetchData();   
  }, [data]);   <---- ** problem ** with data(dependency),
                                    infinite request(call) fetchData()
  
  ...
  }
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

what's the reason for infinite loop if there's a dependency. as far as i know, when dependency(data) change, re-render. but useEffect keep asking for data(axios.get(~~)). if i leave a comment, i can see normally the latest comments, but the network tab(in develop tools) keeps asking for data(304 Not Modified, under image)

enter image description here

CodePudding user response:

There's an infinite loop because that code says "If data changes, request information from the server and change data." The second half of that changes data, which triggers the first half again.

You're not using data in the callback, so it shouldn't be a dependency. Just remove it:

useEffect(() => {
    async function fetchData() {
        const response = await _axios.get("/reply/"   id);
        setData(response.data);
    }
    fetchData();   
}, []);
// ^^−−−−−−−−−− don't put `data` here

That gives you a blank dependency array, which will run the effect only when the component first mounts. (If you want to run it again after mount, use a different state member for that, or define fetchData outside the effect and use it both in the effect and at the other time you want to fetch data.)


Side note: Nothing in your code is handling rejections from your fetchData function, which will cause "unhandled rejection" errors. You'll want to hook up a rejection handler to report or suppress the error.

CodePudding user response:

You are using setData after the response which causes the data to change and hence the useEffect(() => {<>your code<>} ,[data]) to fire again.

use useEffect(() => {<>your code<>},[]) if you want to execute the AJAX call only once after component mounting

or

use useEffect(() => {<>your code<>}) without the dependency if you want to execute the AJAX call after the component mount and after every update

CodePudding user response:

Dependencies argument of useEffect is useEffect(callback, dependencies)

Let's explore side effects and runs:

Not provided: the side-effect runs after every rendering.

import { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    // Runs after EVERY rendering
  });  
}

An empty array []: the side-effect runs once after the initial rendering.

import { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    // Runs ONCE after initial rendering
  }, []);
}

Has props or state values [prop1, prop2, ..., state1, state2]: the side-effect runs only when any dependency value changes.

import { useEffect, useState } from 'react';

function MyComponent({ prop }) {
  const [state, setState] = useState('');
  useEffect(() => {
    // Runs ONCE after initial rendering
    // and after every rendering ONLY IF `prop` or `state` changes
  }, [prop, state]);
}
  • Related