简体   繁体   中英

React useEffect infinite loop

I was experimenting with React a little and wanted to retrieve a json file I had on S3 bucket. I'm using the next code

import React, { useState, useEffect } from "react";
import { Storage } from "aws-amplify";

export default function Gallery(props){
  const [picList, setPicList] = useState([]);

  useEffect(() => {
    async function onLoad() {
      try{
        const picUrl = await Storage.get('list.json');
        const picr = await fetch(picUrl);
        const picjs = await picr.json();
        setPicList(picjs);
        console.log(picList);
      }
      catch(e){
        alert(e);
      }
    };
    onLoad();
  }, [picList]);



  function renderLander() {
    return (
      <div className="lander">
        <h1>Lander</h1>
      </div>
    );
  }

  return(
    <div className="Gallery">
      {renderLander()}
    </div>
  );
}

In the begining I was getting the error that when using setPicList , picList doesn't take the value of json file. I'm using console.log() to debug, so I'm sure that Storage.get is getting the right url, fetch() is getting the file json, but picList prints the default value [] .

Now, with the code above instead I'm getting an infinite loop, but this time the value of picList is getting the right value (but it keeps fetching S3 for every render I think).

I was following this guide

Edit: for completeness, picList is not getting updated if I remove the dependency, ie if I let [] instead of [picList] .

As Brian mentioned before, your useEffect is set to trigger whenever picList is changed. Since picList is being changed inside useEffect, this creates an infinite loop.

Since you're retrieving an object from S3, all you need to do is retrieve it once.

useEffect(() => {
    ...
}, []);

Ensures that the useEffect will only run once, when first rendered

React hooks changes states asynchronously, so console.logging right after will produce either None or the previous value.

What you need to do is add a conditional statement to your render function, to re-render the component when the state updates.

function renderLander() {
    return (
      <div className="lander">
        <h1>Lander</h1>
      </div>
    );
  }

  return(
    <div className="Gallery">
      {picList ? renderLander() : null}
    </div>
  );

You call setPicList in the callback function that listens for side effects off picList :

useEffect(() => {
    setPicList(someValue); //infinite loop because this causes a side effect
}, [picList]);

You are listening for changes to picList with useEffect and than make changes to picList when there is a change to picList in your useEffect call back function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM