0

This code give me infinite loop at line console.log

const userInfo = JSON.parse(localStorage.getItem("user_info"));
const [filterSemester, setFilterSemester] = useState(SEMESTERS[0]);
const [scoreData, setScoreData] = useState(null);

useEffect(() => {
  getData();
}, [userInfo, filterSemester]);

useEffect(() => {
  console.log("scoreData: ", scoreData);
}, [scoreData]);

const getData = () => {
  const params = {
    student_id: userInfo?.student_info?.id,
    school_year_id:
      userInfo?.student_info?.class_info?.grade_info?.school_year_id,
    semester: filterSemester.key,
  };
  getStudyInfoBySchoolYear(params).then((res) => {
    if (res?.status === 200) {
      setScoreData(res?.data?.data);
    }
  });
};

If I remove userInfo from the dependency array of the first useEffect, the loop will gone, I wonder why? I didn't change it at all in the code.

Huan Huynh
  • 399
  • 6
  • 16

2 Answers2

2

userInfo is actually changing.

It is a functional component, so all the code that is inside the component will run on every render, thus, userInfo gets re-created on every render, because it was not declared as a reference (with useRef) or, more commonly, as a state (with useState).

The flow is as follows:

  1. The component mounts.
  2. The first useEffect runs getData. The second useEffect also runs.
  3. getData will update scoreData state with setScoreData. This latter will trigger a re-render, and also scoreData has changed, so the second useEffect will run.
  4. When the render takes place, all the code within your component will run, including the userInfo declaration (creating a new reference to it, unless localStorage.getItem("user_info") is returning undefined).
  5. React detects userInfo as changed, so the first useEffect will run again.
  6. The process repeats from step 3.

You could replace your

const userInfo = JSON.parse(localStorage.getItem("user_info"));

with

  const userInfo = React.useRef(JSON.parse(localStorage.getItem("user_info")));

and your

useEffect(() => {
  getData();
}, [userInfo, filterSemester]);

with

  useEffect(() => {
    getData();
  }, [userInfo.current, filterSemester]);
eineComadreja
  • 166
  • 1
  • 7
1

try this

const userInfo = JSON.parse(localStorage.getItem("user_info"));
const [filterSemester, setFilterSemester] = useState(SEMESTERS[0]);
const [scoreData, setScoreData] = useState(null);

useEffect(() => {
  getData();
}, [localStorage.getItem("user_info"), filterSemester]);

useEffect(() => {
  console.log("scoreData: ", scoreData);
}, [scoreData]);

const getData = () => {
  const params = {
    student_id: userInfo?.student_info?.id,
    school_year_id:
      userInfo?.student_info?.class_info?.grade_info?.school_year_id,
    semester: filterSemester.key,
  };
  getStudyInfoBySchoolYear(params).then((res) => {
    if (res?.status === 200) {
      setScoreData(res?.data?.data);
    }
  });
};
anaval
  • 1,130
  • 10
  • 24