使用 fetch API 获取数据和 setState 时 React useEffect 循环多次

cki*_*ris 0 javascript reactjs fetch-api use-effect use-state

为什么会fetchData多次触发?在console.log似乎环几乎是无限?如何让它在加载时仅运行一次并在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]);
Run Code Online (Sandbox Code Playgroud)

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

return (
    <select>
        {data.map((value, index) => {
            return <option key={index}>{value}</option>
        })}
    </select>
)
Run Code Online (Sandbox Code Playgroud)

sub*_*tra 5

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()

}, [])

Run Code Online (Sandbox Code Playgroud)

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

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()

}, [])

Run Code Online (Sandbox Code Playgroud)

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

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

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

useEffect(() => {
  console.log(data)
}, [data])
Run Code Online (Sandbox Code Playgroud)

但是如果由于某种原因你必须初始化dataas的值null。以下是呈现从 API 调用返回的信息的方法。

const [data, setData] = useState([]);
Run Code Online (Sandbox Code Playgroud)

不要使用indexesas key,为密钥使用唯一的东西。