使用 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】:
多个状态更新是批处理的,但前提是它从事件处理程序中同步发生,而不是setTimeouts
或async-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的主要内容,如果未能解决你的问题,请参考以下文章
如何比较 React Hooks useEffect 上的 oldValues 和 newValues?多次重新渲染