反应useEffect无限循环

时间:2019-12-02 21:11:59

标签: javascript reactjs aws-amplify

我正在对React进行一些试验,并想检索我在S3存储桶中拥有的json文件。我正在使用下一个代码

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

在一开始,我得到一个错误,即使用setPicList时,picList没有采用json文件的值。我正在使用console.log()进行调试,因此我确定Storage.get正在获取正确的url,fetch()正在获取文件json,但是picList打印出默认值[]

现在,使用上面的代码代替,我得到了一个无限循环,但是这次picList的值得到了正确的值(但是我想为每个渲染都继续获取S3)。

我正在关注this guide

编辑:出于完整性考虑,如果删除依赖项,即picList而不是[][picList]不会更新。

2 个答案:

答案 0 :(得分:3)

如Brian所述,您的useEffect设置为在picList更改时触发。由于在useEffect中更改了picList,因此将创建一个无限循环。

由于您要从S3检索对象,因此您只需要做一次检索即可。

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

确保useEffect在首次呈现时仅运行一次

React钩子异步更改状态,因此,在console.logging之后立即生成None或前一个值。

您需要做的是在渲染函数中添加条件语句,以便在状态更新时重新渲染组件。

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

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

答案 1 :(得分:1)

您在回调函数中调用setPicList,以监听picList的副作用:

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

您正在监听picListuseEffect的更改,而当picList回调中picList发生更改时,您将对useEffect进行更改功能。