React中useEffect钩子函数异步获取数据

3

我正在尝试通过useEffect中的异步方法加载数据。我传递所有必要的依赖项,并且据我理解,useEffect应该在组件挂载时、第一次渲染时以及依赖项更改时工作。

useEffect(() => { 
        console.log('effect')
        if (ids.length === 0) {
            api.images.all().then((data) => { console.log(data); setIDs(data) }).catch(console.log)
        }
    }, [ids])

在我的情况下,它会触发3次:挂载(应立即加载数据),第一次渲染(不应进入if语句),以及由于ID更改而触发的(也不应进入if语句)。但useEffect会触发4次,并且会加载数据两次,我无法弄清楚为什么。

enter image description here

组件代码:
//BuildIn
import { useEffect, useState } from 'react'
//Inside
import api from '../services/api.service'
import AsyncImage from '../components/AsyncImage.component'

const ImagesPage = () => {
    const [ids, setIDs] = useState([])

    useEffect(() => { 
        console.log('effect')
        if (ids.length === 0) {
            api.images.all().then((data) => { console.log(data); setIDs(data) }).catch(console.log)
        }
    }, [ids])

    return(
        <>
            {(ids.length > 0) ? ids.map((id, index) => <AsyncImage guid={id} key={index} />) : <div>No data</div>}
        </>
    )
}

export default ImagesPage

2
看看这个答案,我最近回答了它 -> https://dev59.com/EHcPtIcB2Jgan1znKWtC#73011686。由于严格模式,你才会得到这种行为。 - Mridul Gupta
它解决了你的问题吗?@РоманМатвеев - Mridul Gupta
2个回答

2
我已经重新实现了你的示例中的业务逻辑,并且它运行良好。唯一需要修复的问题是将setIDs作为依赖项传递给useEffect。组件渲染两次是可以接受的;第一次是初始渲染,第二次在数据存在时发生。
你甚至可以摆脱if条件。只需不将id传递给useEffect钩子,它就会仅在挂载时获取图像。

// import { useState, useEffect } from 'react' --> with babel import
const { useState, useEffect } = React  // --> with inline script tag

const api = {
  images: { all: () => new Promise(res => res(['id1', 'id2'])) }
}

const ImagesPage = () => {
    const [ids, setIDs] = useState([])

    useEffect(() => { 
      api.images.all()
      .then(data => {
        setIDs(data)
      })
      .catch(console.log)
    }, [setIDs])

    return(
      <ul>
        {console.log('reders')}
        {ids.map(id => <li key={id}>{id}</li>)}
      </ul>
    )
}

ReactDOM.render(<ImagesPage />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>


1
谢谢你的回答!我在StrictMode上工作,那就是问题所在。但是你的回答也帮了我很多。再次感谢! - Pedro

0
尝试做这个:
useEffect(() => {
    async function fetchData() {
      const res = await loadMovies();
      setIDs(res)
    }
    fetchData();
  }, []);

谢谢回答,但是它并没有帮助到我。 - Pedro
感谢您提供这段代码片段,它可能会提供一些有限的即时帮助。适当的解释将极大地提高其长期价值,展示为什么这是一个好的问题解决方案,并使其对未来的读者更加有用,这些读者可能会有其他类似的问题。请在回答中添加一些解释,包括您所做的假设。 - jasie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接