【问题标题】:React useEffect looping many times when fetching data and setState using fetch API使用 fetch API 获取数据和 setState 时反应 useEffect 循环多次
【发布时间】:2020-10-04 10:13:06
【问题描述】:

为什么会多次触发fetchDataconsole.log 似乎几乎无限循环?我如何让它只运行一次 onload 并在以后调用fetchData() 时只触发一次?我在这里做错了什么或错过了什么?

const [data, setData] = useState(null);

  let fetchData = React.useCallback(async () => {
    const result = await fetch(`api/data/get`);
    const body = await result.json();
    setData(body);
    console.log(data)
  },[data])

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

更新(附加问题):如何在return() 之前等待data 填充现在下面的这个现在给出了错误,因为它一开始是空的?:data.map is not a function

return (
    <select>
        {data.map((value, index) => {
            return <option key={index}>{value}</option>
        })}
    </select>
)

【问题讨论】:

    标签: javascript reactjs fetch-api use-effect use-state


    【解决方案1】:

    useCallback 挂钩中,您将data 作为依赖项传递,并同时通过调用setData 更改回调中的数据值,这意味着每次更改fetchData 的数据值时都会重新初始化。

    useEffect 钩子中fetchData 是一个依赖项,这意味着每次fetchData 更改useEffect 都会被触发。这就是你得到一个无限循环的原因。

    因为你想在组件挂载时获取一次数据,所以我认为useCallback在这里是不必要的。无需记忆函数fetchData

    解决方案

    const [data, setData] = useState(null);
    
    useEffect(() => {
      const fetchData = async () => {
        try {
         const result = await fetch(`api/data/get`);
         const body = await result.json();
         setData(body);
        } catch(err) {
          // error handling code
        } 
      }
    
      // call the async fetchData function
      fetchData()
    
    }, [])
    
    

    如果您想在 data 的值更改时记录它,您可以使用另一个 useEffect 来代替它。例如,

    useEffect(() => {
      console.log(data)
    }, [data])
    

    附: - 也不要让承诺得不到处理,请使用try...catch 块来处理错误。我已更新解决方案以包含 try..catch 块。

    编辑 - 附加问题的解决方案 有两种可能的解决方案,

    因为您希望 data 的值在 API 调用之后是一个数组,所以您可以将 data 的值初始化为一个空数组,例如,

    const [data, setData] = useState([]);
    

    但是如果由于某种原因您必须将data 的值初始化为null。以下是如何呈现从 API 调用返回的信息。

    // using short-circuit evaluation
    return (
        <select>
            {data && data.length && data.map((value) => {
                return <option key={`select-option-${value}`}>{value}</option>
            })}
        </select>
    )
    
    
    // using a ternary
    return (
       <div>
        { data && data.length
           ? (<select>
                {
                  data.map(value => <option key={`select-option-${value}`}>{value}</option>)
                }
               </select>
             )
           : <div>Data is still loading...</div>
        }
       </div>
    )
    

    不要将indexes 用作key,使用独特的东西作为键。

    【讨论】:

    • if then 在return ( &lt;div&gt;{orgList}&lt;/div&gt; ) 中呈现该数据(这只是示例)。它说:Cannot read property of null 我猜是因为在组件渲染之前 fetch 调用还没有完成?
    • 发生这种情况是因为data 在第一次渲染时仍然是null。 fetch 调用发生在组件安装后。解决方案是在尝试访问其属性之前检查数据是否存在,您可以通过使用三元运算符或类似这样的短路评估来实现这一点,{ data &amp;&amp; &lt;div&gt;{data.anyPropertyofData}&lt;/div&gt;}
    • 我更新了上面的问题,你能展示如何实现三元运算符吗?谢谢你,感谢你的所有帮助
    • 根据您的要求更新了答案,请看一下。
    猜你喜欢
    • 2022-01-12
    • 2021-11-04
    • 1970-01-01
    • 1970-01-01
    • 2020-07-25
    • 2018-06-10
    • 1970-01-01
    • 1970-01-01
    • 2021-08-29
    相关资源
    最近更新 更多