使用 React Hooks 多次获取数据 axios

Posted

技术标签:

【中文标题】使用 React Hooks 多次获取数据 axios【英文标题】:Multiple fetch data axios with React Hooks 【发布时间】:2019-08-26 13:29:19 【问题描述】:

我想从 Github 用户和他的 repos 那里获取全球信息(并且获得 pinned repos 会很棒)。我尝试使用异步等待来实现它,但它是正确的吗?我有 4 次重新渲染(4 次控制台日志)。获取所有数据后是否可以等待所有组件重新渲染?

function App() 
  const [data, setData] = useState(null);
  const [repos, setRepos] = useState(null);

  useEffect(() => 
    const fetchData = async () => 
      const respGlobal = await axios(`https://api.github.com/users/$username`);
      const respRepos = await axios(`https://api.github.com/users/$username/repos`);

      setData(respGlobal.data);
      setRepos(respRepos.data);
    ;

    fetchData()

  , []);

  if (data) 
    console.log(data, repos);
  

  return (<h1>Hello</h1>)

【问题讨论】:

我以前从未见过 React Hooks,哎呀。但是您查看过async series 文档吗?它允许您一个接一个地进行调用,然后您可以在每次 axios 请求成功后在回调中 setState 【参考方案1】:

多个状态更新是批处理的,但前提是它从事件处理程序中同步发生,而不是setTimeoutsasync-await wrapped methods

此行为类似于类,因为在您的情况下,由于发生两个状态更新调用,它执行两个状态更新周期

所以最初你有一个初始渲染,然后你有两次状态更新,这就是组件渲染三次的原因。

由于您的案例中的两个状态是相关的,您可以像这样创建一个对象并一起更新它们:

function App() 
  const [resp, setGitData] = useState( data: null, repos: null );

  useEffect(() => 
    const fetchData = async () => 
      const respGlobal = await axios(
        `https://api.github.com/users/$username`
      );
      const respRepos = await axios(
        `https://api.github.com/users/$username/repos`
      );

      setGitData( data: respGlobal.data, repos: respGlobal.data );
    ;

    fetchData();
  , []);

  console.log('render');
  if (resp.data) 
    console.log("d", resp.data, resp.repos);
  

  return <h1>Hello</h1>;

Working demo

【讨论】:

答案有效,但有一种更优雅的方式。你可以使用const [respGlobal, respRepos] = await Promise.all([ axios(api.github.com/users/$username), axios(api.github.com/users/$username/repos) ]); 如果 2 个 api 调用不相关,你会怎么做?在这种情况下,调用 /users,我们等到它完成后再调用 /users/x/repos。如果数据彼此独立怎么办?我不想一个人等另一个人。有这种模式吗?我认为@F***Hinsenkamp 的回答存在同样的“问题”【参考方案2】:

对于其他研究人员 (Live demo):

import React,  useEffect, useState  from "react";
import  CPromise, CanceledError  from "c-promise2";
import cpAxios from "cp-axios";

function MyComponent(props) 
  const [error, setError] = useState("");
  const [data, setData] = useState(null);
  const [repos, setRepos] = useState(null);

  useEffect(() => 
    console.log("mount");
    const promise = CPromise.from(function* () 
      try 
        console.log("fetch");
        const [respGlobal, respRepos] = [
          yield cpAxios(`https://api.github.com/users/$props.username`),
          yield cpAxios(`https://api.github.com/users/$props.username/repos`)
        ];

        setData(respGlobal.data);
        setRepos(respRepos.data);
       catch (err) 
        console.warn(err);
        CanceledError.rethrow(err); //passthrough
        // handle other errors than CanceledError
        setError(err + "");
      
    , []);

    return () => 
      console.log("unmount");
      promise.cancel();
    ;
  , [props.username]);

  return (
    <div>
      error ? (
        <span>error</span>
      ) : (
        <ul>
          <li>JSON.stringify(data)</li>
          <li>JSON.stringify(repos)</li>
        </ul>
      )
    </div>
  );

【讨论】:

【参考方案3】:
function App() 
  const [resp, setGitData] = useState( data: null, repos: null );

  useEffect(() => 
    const fetchData = async () => 
      const respGlobal = await axios(
        `https://api.github.com/users/$username`
      );
      const respRepos = await axios(
        `https://api.github.com/users/$username/repos`
      );

      setGitData( data: respGlobal.data, repos: respGlobal.data );
    ;

    fetchData();
  , []);

  console.log('render');
  if (resp.data) 
    console.log("d", resp.data, resp.repos);
  

  return <h1>Hello</h1>;


he made some mistake here:
setGitData( data: respGlobal.data, repos: respGlobal.data(respRepos.data //it should be respRepos.data);

【讨论】:

【参考方案4】:

我想我会尝试一下,因为上面的答案很好,但是,我喜欢清洁。

import React,  useState, useEffect  from 'react'
import axios from 'axios'

const Test = () => 
    const [data, setData] = useState([])

    useEffect(() => 
        (async () => 
            const data1 = await axios.get('https://jsonplaceholder.typicode.com/todos/1')
            const data2 = await axios.get('https://jsonplaceholder.typicode.com/todos/2')
            setData(data1, data2)
        )()
    , [])

    return JSON.stringify(data)


export default Test

使用自调用函数可以省去在 useEffect 中调用函数的额外步骤,这有时会在 WebStorm 和 phpStorm 等 IDE 中引发 Promise 错误。

【讨论】:

以上是关于使用 React Hooks 多次获取数据 axios的主要内容,如果未能解决你的问题,请参考以下文章

测试使用 Hooks 获取数据的 React 组件

[react] 怎样使用Hooks获取服务端数据?

React hooks之useEffect

如何比较 React Hooks useEffect 上的 oldValues 和 newValues?多次重新渲染

React-firestore-hooks 从云 Firestore 中获取数据库记录

使用 React Hooks useEffect 发送 ajax 请求获取数据全攻略