Home > other >  ReactJS - use localStorage as a dependency for useEffect causes infinite loop
ReactJS - use localStorage as a dependency for useEffect causes infinite loop

Time:02-23

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.

CodePudding user response:

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);
    }
  });
};

CodePudding user response:

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]);
  • Related