点击上方“蓝字”带你每天阅读全栈前端精选好文
原文地址:robinwieruch
在本教程中,我想向你展示如何使用 state 和 effect 钩子在React中获取数据。 你还将实现自定义的 hooks 来获取数据,可以在应用程序的任何位置重用,也可以作为独立节点包在npm上发布。
如果你对 React 的新功能一无所知,可以查看 React hooks 的相关 api 介绍。如果你想查看完整的如何使用 React Hooks 获取数据的项目代码,可以查看 github 的仓库
如果你只是想用 React Hooks 进行数据的获取,直接 npm i use-data-api
并根据文档进行操作。如果你使用他,别忘记给我个star 哦~
注意:将来,React Hooks 不适用于 React 中获取数据。一个名为Suspense的功能将负责它。以下演练是了解React中有关 state 和 Effect hooks 的更多信息的好方法。
使用 React hooks 获取数据
如果您不熟悉React中的数据提取,请查看我在React文章中提取的大量数据。它将引导您完成使用React类组件的数据获取,如何使用Render Prop 组件和高阶组件来复用这些数据,以及它如何处理错误以及 loading 的。
1 import React, { useState } from 'react';
2
3 function App() {
4 const [data, setData] = useState({ hits: [] });
5
6 return (
7 <ul>
8 {data.hits.map(item => (
9 <li key={item.objectID}>
10 <a href={item.url}>{item.title}</a>
11 </li>
12 ))}
13 </ul>
14 );
15 }
16
17 export default App;
App 组件显示了一个项目列表(hits=Hacker News 文章)。状态和状态更新函数来自useState 的 hook。他是来负责管理我们这个 data 的状态的。userState 中的第一个值是data 的初始值。其实就是个解构赋值。
这里我们使用 axios 来获取数据,当然,你也可以使用别的开源库。
1import React, { useState, useEffect } from 'react';
2import axios from 'axios';
3
4function App() {
5 const [data, setData] = useState({ hits: [] });
6
7 useEffect(async () => {
8 const result = await axios(
9 'https://hn.algolia.com/api/v1/search?query=redux',
10 );
11
12 setData(result.data);
13 });
14
15 return (
16 <ul>
17 {data.hits.map(item => (
18 <li key={item.objectID}>
19 <a href={item.url}>{item.title}</a>
20 </li>
21 ))}
22 </ul>
23 );
24}
25
26export default App;
这里我们使用 useEffect 的 effect hook 来获取数据。并且使用 useState 中的 setData 来更新组件状态。
但是如上代码运行的时候,你会发现一个特别烦人的循环问题。effect hook 的触发不仅仅是在组件第一次加载的时候,还有在每一次更新的时候也会触发。由于我们在获取到数据后就进行设置了组件状态,然后又触发了 effect hook。所以就会出现死循环。很显然,这是一个 bug!我们只想在组件第一次加载的时候获取数据 ,这也就是为什么你可以提供一个空数组作为 useEffect
的第二个参数以避免在组件更新的时候也触发它。当然,这样的话,也就是在组件加载的时候触发。
1 import React, { useState, useEffect } from 'react';
2 import axios from 'axios';
3
4 function App() {
5 const [data, setData] = useState({ hits: [] });
6
7 useEffect(async () => {
8 const result = await axios(
9 'https://hn.algolia.com/api/v1/search?query=redux',
10 );
11
12 setData(result.data);
13 }, []);
14
15 return (
16 <ul>
17 {data.hits.map(item => (
18 <li key={item.objectID}>
19 <a href={item.url}>{item.title}</a>
20 </li>
21 ))}
22 </ul>
23 );
24 }
25
26 export default App;
第二个参数可以用来定义 hook 所依赖的所有变量(在这个数组中),如果其中一个变量发生变化,则就会触发这个 hook 的运行。如果传递的是一个空数组,则仅仅在第一次加载的时候运行。
是不是感觉 ,干了
shouldComponentUpdate
的事情
这里还有一个陷阱。在这个代码里面,我们使用 async/await
去获取第三方的 API 的接口数据,根据文档,每一个 async
都会返回一个 promise:async
函数声明定义了一个异步函数,它返回一个 AsyncFunction 对象。异步函数是通过事件循环异步操作的函数,使用隐式的 Promise 返回结果然而,effect hook 不应该返回任何内容,或者清除功能。这也就是为啥你看到了
这个警告:
07:41:22.910 index.js:1452 Warning: useEffect function must return a cleanup function or nothing. Promises and useEffect(async () => …) are not supported, but you can call an async function inside an effect.. ``
这就是为什么我们不能在useEffect
中使用 async
的原因。但是我们可以通过如下方法解决:
1 import React, { useState, useEffect } from 'react';
2 import axios from 'axios';
3
4 function App() {
5 const [data, setData] = useState({ hits: [] });
6
7 useEffect(() => {
8 const fetchData = async () => {
9 const result = await axios(
10 'https://hn.algolia.com/api/v1/search?query=redux',
11 );
12
13 setData(result.data);
14 };
15
16 fetchData();
17 }, []);
18
19 return (
20 <ul>
21 {data.hits.map(item => (
22 <li key={item.objectID}>
23 <a h