使用 UseEffect Hook 获取 API

Posted

技术标签:

【中文标题】使用 UseEffect Hook 获取 API【英文标题】:Using UseEffect Hook to Fetch API 【发布时间】:2021-03-11 06:10:51 【问题描述】:

我正在尝试通过使用提取的信息更新我的状态来从 api 获取加密货币数据。但是当我这样做时,我的 console.log 显示一个空对象。也没有数据传递给我的子组件。我在这里做错了吗?

import React, useState, useEffect from 'react';
import SmallBox from './SmallBox';
import './App.css';

function App() 
  const [smallData, setSmallData] = useState()

  async function getAPI()
    await fetch(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=false
    `)
    .then(response => response.json())
    .then(data => setSmallData(data)); 
  

  useEffect( () => 
    getAPI();
    console.log(smallData)
  , []);


  return (
    <div className="app">
      
      /* SmallBox - balance */
      <SmallBox className="balance"/>
      
      /* SmallBox - bitcoin */
      <SmallBox className="bitcoin" coin=smallData/>
      
      /* SmallBox - ethereum */
      <SmallBox className="ethereum" coin=smallData/>
      
      /* SmallBox - ripple */
      <SmallBox className="ripple" coin=smallData/>
      
      /* SmallBox - tether */
      <SmallBox className="tether" coin=smallData/>
     
    </div>
  );


export default App;

【问题讨论】:

getAPI 是一个 async 函数。当您调用console.log 时,状态尚未更新。 您的 API 调用和响应状态更改都是异步的,您可以在下一行打印状态值并查看更新 【参考方案1】:

试试这个:

async function getAPI()
    const rawData = await fetch(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=false`)
    const jsonData = rawData.json();
    setSmallData( state => (...jsonData) );
  

useEffect(() => 
    getAPI().then(() => console.log(smallData));
  , []);

【讨论】:

【参考方案2】:

在记录数据之前尝试awaiting 获取要获取的数据,而不是在async 函数getAPI 中等待获取:

  function getAPI()
    return fetch(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=false
    `)
      .then(response => response.json())
      .then(data => setSmallData(data)); 
  

  useEffect( () => 
    await getAPI();
    console.log(smallData)
  , []); // <- Add dependencies here

注意:我认为 getAPI 将在组件的每个渲染中被调用,我认为这不是你想要的。我建议为传递给useEffect 函数的第二个变量(一个空数组)添加一些依赖项,告诉 React 只有在那个/那些变量发生变化时才调用这个效果。例如,您可以添加货币。

【讨论】:

【参考方案3】:

更改 useEffect 等待 getApi 函数完成。

  useEffect(() => 
    getAPI().then((_) => 
      console.log(smallData);
    );
  , []);

【讨论】:

【参考方案4】:

首先,您的console.log 应该显示,因为这是smallData 的初始状态,getAPI 将异步执行。这没有什么不妥。

但是由于您没有将数据传递给子组件的问题,可能是因为您将 smallData 设置为 data: *api response* ,也许您希望 smallData 成为 api 响应,而不是带有data 属性。

我建议将 console.log(smallData) 放在 return 语句之前,以便在每次渲染中查看其内容。

如果还是遇到问题,添加SmallBox组件代码,可能问题就出在这里

【讨论】:

【参考方案5】:

您的 React 设置状态挂钩是异步调用的。因此,您的 smallData 将显示之前的状态,因为组件尚未重新渲染。

你没有做错任何事。请参阅下面的注释代码以了解发生了什么。

  useEffect( () => 
    getAPI(); // 1. This call seems to be correct, and queues up setSmallData. 
    // 2. The state update has not happened yet, but the setSmallData call is queued up. 
    console.log(smallData) // 3. still  because the state has not been updated yet, and thus is still showing the current state. 

  , []);

换句话说,console.log(smallData) 在你的 setSmallData 之前运行,这就是你看到一个空对象的原因(因为 是你的初始状态)。但是,如果您在页面的某处显示数据,您会注意到组件会随数据一起重新呈现。

你可以试试:

    async function getAPI()
      return await fetch(`...`)
      .then(response => response.json())
      .then(data => data); 
    
    useEffect( () => 
     async function getApiAndSetState() 
     let data = await getAPI(); // the code pauses here until getAPI() completes.
     console.log(data); // this data is now available
     setSmallData(data);
     
   , []);

【讨论】:

以上是关于使用 UseEffect Hook 获取 API的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 useEffect() 更改 React-Hook-Form defaultValue?

我无法获取 localStorage 数据,我正在使用 useEffect Hook

React Hook useEffect :使用 axios 和 async await .api 获取数据,调用连续相同的 api

如何在 React Native 应用程序中使用 React hook useEffect 为每 5 秒渲染设置间隔?

hook函数之useEffect的使用——自定义hook函数网络请求——

如何在 React 中使用 useEffect hook 和 async/await 检索嵌套的 JSON 数据