做网站推广的 什么是开户,谁有做爰网站号,重庆网站推广联系方式,经营性质网站相关说明#xff1a; 对于hook相关词不翻译#xff0c;感觉翻译后怪怪的。 effect hook 效果钩子#xff0c;用于执行一些副作用例如获取数据 。 state hook 状态钩子。 使用----------- 和 ----------- 标出代码需要关注的地方。
渣翻译如下#xff1a;
在这个指南中…相关说明 对于hook相关词不翻译感觉翻译后怪怪的。 effect hook 效果钩子用于执行一些副作用例如获取数据 。 state hook 状态钩子。 使用----------- 和 ----------- 标出代码需要关注的地方。
渣翻译如下
在这个指南中我想给你展示使用state和effect hook在React hooks中如何获取数据。我们将使用著名的 Hacker News API从高科技世界中获取受欢迎的文章。你也可以为获取数据实现自定义获取数据的hook这个hook可以在你的应用中任何地方重用也可以作为一个独立的node包发布到npm上。
如果关于react的新特性你什么都不知道可以查看这篇文章introduction to React Hooks。如果你想查看怎么通过React Hooks获取数据例子的完整项目查看这个GitHub 仓库。
如果你只是想在使用React Hook获取数据前有一个准备npm install use-data-api 并且参照这个文档。如果你采用了不要忘了小星星哦:-)。
**注**在未来React没有计划为获取数据添加专门的Hooks。反而Suspense将会负责这个功能。下面的预演是学习react中关于state和effect hooks一个比较好的方法。
使用React Hooks获取数据
如果你不熟悉在React中获取数据查看我的在react中获取大量的数据这篇文章。这篇文章会引导你使用React Comopnent 类获取数据怎么样可以让获取数据的逻辑通过 Render Prop Components 和 Higher-Order Components重用并且怎么处理重用加载出错和加载中的状态。在这篇文章中我想给你展示以上这些通过React Hooks在函数式组件中的做法。
import React, { useState } from react;function App() {const [data, setData] useState({ hits: [] });return (ul{data.hits.map(item (li key{item.objectID}a href{item.url}{item.title}/a/li))}/ul);
}export default App这个App组件展示了项目列表hits 是 Hacker News 的文章。这个state和跟新state的函数来自于状态钩子useState的调用它的责任是管理本地我们将要为App组件获取的数据数据的状态初始状态的数据是一个对象中的空列表。还没有人为这个数据设置任何状态。
我们将使用axios去获取数据但是是使用其他获取数据的库还是使用浏览器原生的fetch API由你决定。如果你还没有安装axios你可以在命令行输入npm install axios。然后实现你自己的获取数据的effect hook。
// -------------------------------------------------
import React, { useState, useEffect } from react;
import axios from axios;
// -------------------------------------------------function App() {const [data, setData] useState({ hits: [] });// -------------------------------------------------useEffect(async () {const result await axios(http://hn.algolia.com/api/v1/search?queryredux,);setData(result.data);});// -------------------------------------------------return (ul{data.hits.map(item (li key{item.objectID}a href{item.url}{item.title}/a/li))}/ul);
}export default App;名为useEffect的effect hook被用于使用axios从接口获取数据并且通过状态钩子的更新函数设置数据到组件的本地状态中。promise 通过 async/await中 被 resolve。
然而当你运行你的应用的的时候你应该会陷入一个令人讨厌的循环。effect hook会在组件挂载的时候运行但是也会在组件跟新的时候运行。因为我们在每次获取数据之后设置状态然后组件跟新然后effect hook再次运行。组件将会一次又一次的获取数据。这是一个需要避免的问题。我们只希望在组件挂载的时候获取数据。
这就是为什么你需要提供一个空数组作为effect hook的第二个参数的原因是为了阻止在组件更新的时候激活它只在组件挂载的时候激活它。
import React, { useState, useEffect } from react;
import axios from axios;function App() {const [data, setData] useState({ hits: [] });useEffect(async () {const result await axios(http://hn.algolia.com/api/v1/search?queryredux,);setData(result.data);// -------------------------------------------------}, []);// -------------------------------------------------return (ul{data.hits.map(item (li key{item.objectID}a href{item.url}{item.title}/a/li))}/ul);
}export default App;第二个参数被用于定义钩子依赖的所有变量分配到这个数组中。如果有一个变量改变钩子会再次运行。如果数组中没有变量这个钩子在组件更新的时候就不会运行因为它没有监听任何变量。
还有最后一个问题。在代码中我们使用async/await从第三方接口获取数据。根据文档表述每个使用async注释的函数都会返回一个隐含的promise对象async函数声明定义一个异步函数返回一个异步函数对象。*An asynchronous function is a function which operates asynchronously via the event loop, *异步函数是一个操作通过事件循环操作异步的函数使用隐式的Promise作为结果返回”。However, an effect hook should return nothing or a clean up function.然而一个effect hook不应该返回值或者返回一个清除函数。这是个啥return nothing这就是为什么在你的开发者日志里面能看见下面的警告 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直接使用异步函数的原因。让我们来修复它通过异步函数取代effect hook。
import React, { useState, useEffect } from react;
import axios from axios;function App() {const [data, setData] useState({ hits: [] });useEffect(() {// -------------------------------------------------const fetchData async () {const result await axios(http://hn.algolia.com/api/v1/search?queryredux,);setData(result.data);};fetchData();// -------------------------------------------------}, []);return (ul{data.hits.map(item (li key{item.objectID}a href{item.url}{item.title}/a/li))}/ul);
}export default App;简而言之这就是在React hooks中获取数据。但是如果你对错误处理加载状态怎么从表单触发数据获取怎么实现一个重用的数据获取钩子感兴趣 请继续阅读。
如何以编程的方式/手动触发钩子
很好我们将会在组件挂载的时候获取一次数据。但是怎么使用输入的字段去告诉接口我们感兴趣的话题呢“Redux“作为默认的查询。但是哪些话题是关于React的呢让我们实现一个输入框去让人能够获取Redux以外的其他信息。因此为输入框引入一个新的状态。
import React, { Fragment, useState, useEffect } from react;
import axios from axios;function App() {const [data, setData] useState({ hits: [] });// -------------------------------------------------const [query, setQuery] useState(redux);// -------------------------------------------------useEffect(() {const fetchData async () {const result await axios(http://hn.algolia.com/api/v1/search?queryredux,);setData(result.data);};fetchData();}, []);return (Fragment{/* ------------------------------------------------- */}inputtypetextvalue{query}onChange{event setQuery(event.target.value)}/{/* ------------------------------------------------- */}ul{data.hits.map(item (li key{item.objectID}a href{item.url}{item.title}/a/li))}/ul/Fragment);
}export default App;目前每个状态都是独立的但是现在你想结合他们只获取通过输入框输入的查询字段指定文章。通过下面的改变组件应该在挂载的时候通过查询字段获取一次所有文章。
...function App() {const [data, setData] useState({ hits: [] });const [query, setQuery] useState(redux);useEffect(() {const fetchData async () {const result await axios(// -------------------------------------------------http://hn.algolia.com/api/v1/search?query${query},// -------------------------------------------------);setData(result.data);};fetchData();}, []);return (...);
}export default App;有一块被遗漏了当你在输入框中输入内容的时候在组件挂在之后effect hook不会获取其他数据。这是因为你用一个空数组作为effect hook函数的第二个参数。这个副作用就没有依赖的变量所以它只在组挂载的时候触发。然而现在effect hook应该依赖query。一旦query改变就应该再次请求数据。
...function App() {const [data, setData] useState({ hits: [] });const [query, setQuery] useState(redux);useEffect(() {const fetchData async () {const result await axios(http://hn.algolia.com/api/v1/search?query${query},);setData(result.data);};fetchData();// -------------------------------------------------}, [query]);// -------------------------------------------------return (...);
}export default App;
在你改变输入框中的值的时候应该获取一次数据。但是它带来了另一个问题你在输入框中输入每一个字符都会触发并执行effect hook然后执行获取其他数据。提供一个按钮去触发请求手动触发钩子怎么样
function App() {const [data, setData] useState({ hits: [] });const [query, setQuery] useState(redux);// -------------------------------------------------const [search, setSearch] useState();// -------------------------------------------------useEffect(() {const fetchData async () {const result await axios(http://hn.algolia.com/api/v1/search?query${query},);setData(result.data);};fetchData();}, [query]);return (Fragmentinputtypetextvalue{query}onChange{event setQuery(event.target.value)}/{/* ------------------------------------------------- */}button typebutton onClick{() setSearch(query)}Search/button{/* ------------------------------------------------- */}ul{data.hits.map(item (li key{item.objectID}a href{item.url}{item.title}/a/li))}/ul/Fragment);
}现在让effect hook依赖search状态而不是根据输入的每个内容波动的query状态用户点击一次按钮新的search状态就会被设置并且应该手动触发一次effect hook。
...function App() {const [data, setData] useState({ hits: [] });const [query, setQuery] useState(redux);// -------------------------------------------------const [search, setSearch] useState(redux);// -------------------------------------------------useEffect(() {const fetchData async () {const result await axios(// -------------------------------------------------http://hn.algolia.com/api/v1/search?query${search},// -------------------------------------------------);setData(result.data);};fetchData();// -------------------------------------------------}, [search]);// -------------------------------------------------return (...);
}export default App;search的初始状态也应该和query的初始状态一样因为组件也会在挂载的时候获取数据因此结果应该和输入的一致。然而query的search状态一样让人有点疑惑。为啥不把search的状态换成真实的URL呢
function App() {const [data, setData] useState({ hits: [] });const [query, setQuery] useState(redux);// -------------------------------------------------const [url, setUrl] useState(http://hn.algolia.com/api/v1/search?queryredux,);// -------------------------------------------------useEffect(() {const fetchData async () {// -------------------------------------------------const result await axios(url);// -------------------------------------------------setData(result.data);};fetchData();// -------------------------------------------------}, [url]);// -------------------------------------------------return (Fragmentinputtypetextvalue{query}{/* ------------------------------------------------- */}onChange{event setQuery(event.target.value)}{/* ------------------------------------------------- */}/buttontypebuttononClick{() setUrl(http://hn.algolia.com/api/v1/search?query${query})}Search/buttonul{data.hits.map(item (li key{item.objectID}a href{item.url}{item.title}/a/li))}/ul/Fragment);
}这就是使用effect hook隐式获取数据的情况。你可以决定这个effect hook依赖哪个状态一旦你在点击的时候或者其他副作用设置这个状态这个effect hook将会再次执行。在这个案例中如果URL状态改变了effect hook会再次执行从接口中获取数据。
React Hooks中的加载指示
让我来介绍一个获取数据的加载指示器。它就是另一个状态钩子state hook管理的状态state。这个加载的标志被用于在App组件中渲染一个加载中的指示器。
import React, { Fragment, useState, useEffect } from react;
import axios from axios;function App() {const [data, setData] useState({ hits: [] });const [query, setQuery] useState(redux);const [url, setUrl] useState(http://hn.algolia.com/api/v1/search?queryredux,);// -------------------------------------------------const [isLoading, setIsLoading] useState(false);// -------------------------------------------------useEffect(() {const fetchData async () {// -------------------------------------------------setIsLoading(true);// -------------------------------------------------const result await axios(url);setData(result.data);// -------------------------------------------------setIsLoading(false);// -------------------------------------------------};fetchData();}, [url]);return (Fragmentinputtypetextvalue{query}onChange{event setQuery(event.target.value)}/buttontypebuttononClick{() setUrl(http://hn.algolia.com/api/v1/search?query${query})}Search/button{/* ------------------------------------------------- */}{isLoading ? (divLoading .../div) : ({/* ------------------------------------------------- */}ul{data.hits.map(item (li key{item.objectID}a href{item.url}{item.title}/a/li))}/ul{/* ------------------------------------------------- */})}{/* ------------------------------------------------- */}/Fragment);
}export default App;当effect hook在组件挂在或者URL状态改变的时候被调用去获取数据这个加载状态就会被设置为true。当请求完成了这个加载状态就会再次被设置为false。
React Hooks的错误处理
在React hook怎么处理获取数据出错呢这个错误只是通过另一个状态钩子初始化的。当这个状态表示出错了这个 App组件可以给用户一个反馈。当使用 async/await常用try/catch块去处理错误。你可以在effect hook里面这样做
import React, { Fragment, useState, useEffect } from react;
import axios from axios;function App() {const [data, setData] useState({ hits: [] });const [query, setQuery] useState(redux);const [url, setUrl] useState(http://hn.algolia.com/api/v1/search?queryredux,);const [isLoading, setIsLoading] useState(false);// -------------------------------------------------const [isError, setIsError] useState(false);// -------------------------------------------------useEffect(() {const fetchData async () {// -------------------------------------------------setIsError(false);// -------------------------------------------------setIsLoading(true);// -------------------------------------------------try {// -------------------------------------------------const result await axios(url);setData(result.data);// -------------------------------------------------} catch (error) {setIsError(true);}// -------------------------------------------------setIsLoading(false);};fetchData();}, [url]);return (Fragmentinputtypetextvalue{query}onChange{event setQuery(event.target.value)}/buttontypebuttononClick{() setUrl(http://hn.algolia.com/api/v1/search?query${query})}Search/button{/* ------------------------------------------------- */}{isError divSomething went wrong .../div}{/* ------------------------------------------------- */}{isLoading ? (divLoading .../div) : (ul{data.hits.map(item (li key{item.objectID}a href{item.url}{item.title}/a/li))}/ul)}/Fragment);
}export default App;这个错误的状态在钩子每次执行的时候都会被重置。这是很有用的因为在失败的请求之后用户回想再次尝试应该重置错误状态。为了检查出错的情况你可以将URL更改为无效的内容。然后查看错误消息是否显示。
通过React和表单的获取数据
在表单中如何获取数据至今我们只组合了input和按钮。当你引入了更多的输入元素你就会想要使用表单元素包裹他们。另外一个表单可能通过键盘的回车键触发按钮触发提交。
function App() {...return (Fragment{/* ------------------------------------------------- */}formonSubmit{() setUrl(http://hn.algolia.com/api/v1/search?query${query})}{/* ------------------------------------------------- */}inputtypetextvalue{query}onChange{event setQuery(event.target.value)}/{/* ------------------------------------------------- */}button typesubmitSearch/button/form{/* ------------------------------------------------- */}{isError divSomething went wrong .../div}.../Fragment);
}但是现在浏览器在你点击提交按钮的时候会刷新因为这是一个浏览器提交表单的原生行为。为了阻止默认行为我们可以调用React事件对象的函数。就像你在React类组件中做的那样。
function App() {...return (Fragment{/* ------------------------------------------------- */}form onSubmit{event {{/* ------------------------------------------------- */}setUrl(http://hn.algolia.com/api/v1/search?query${query});{/* ------------------------------------------------- */}event.preventDefault();}}{/* ------------------------------------------------- */}inputtypetextvalue{query}onChange{event setQuery(event.target.value)}/button typesubmitSearch/button/form{isError divSomething went wrong .../div}.../Fragment);
}现在点击提交按钮的时候浏览器就不会再刷新了。它就像之前那样工作但是这次使用form替换了原生的输入字段和按钮的结合。你也可以在键盘上按回车键提交表单。
自定义获取数据钩子
为了提取一个自定义获取数据的钩子移动每个属于数据获取数据的代码到自己的函数除了属于输入字段的query状态但是包含加载指示器和错误处理。也要确定你在函数中返回了所有App组件里必要的变量。
// -------------------------------------------------
const useHackerNewsApi () {
// -------------------------------------------------const [data, setData] useState({ hits: [] });const [url, setUrl] useState(http://hn.algolia.com/api/v1/search?queryredux,);const [isLoading, setIsLoading] useState(false);const [isError, setIsError] useState(false);useEffect(() {const fetchData async () {setIsError(false);setIsLoading(true);try {const result await axios(url);setData(result.data);} catch (error) {setIsError(true);}setIsLoading(false);};fetchData();}, [url]);
// -------------------------------------------------return [{ data, isLoading, isError }, setUrl];
}
// -------------------------------------------------现在你的新钩子在App组件中又可以使用了。
function App() {const [query, setQuery] useState(redux);// -------------------------------------------------const [{ data, isLoading, isError }, doFetch] useHackerNewsApi();// -------------------------------------------------return (Fragmentform onSubmit{event {{/* ------------------------------------------------- */}doFetch(http://hn.algolia.com/api/v1/search?query${query});{/* ------------------------------------------------- */}event.preventDefault();}}inputtypetextvalue{query}onChange{event setQuery(event.target.value)}/button typesubmitSearch/button/form.../Fragment);
}初始状态也可以通用通过它简化新的自定义钩子。
import React, { Fragment, useState, useEffect } from react;
import axios from axios;// -------------------------------------------------
const useDataApi (initialUrl, initialData) {const [data, setData] useState(initialData);const [url, setUrl] useState(initialUrl);
// -------------------------------------------------const [isLoading, setIsLoading] useState(false);const [isError, setIsError] useState(false);useEffect(() {const fetchData async () {setIsError(false);setIsLoading(true);try {const result await axios(url);setData(result.data);} catch (error) {setIsError(true);}setIsLoading(false);};fetchData();}, [url]);return [{ data, isLoading, isError }, setUrl];
};function App() {const [query, setQuery] useState(redux);// -------------------------------------------------const [{ data, isLoading, isError }, doFetch] useDataApi(http://hn.algolia.com/api/v1/search?queryredux,{ hits: [] },);// -------------------------------------------------return (FragmentformonSubmit{event {doFetch(http://hn.algolia.com/api/v1/search?query${query},);event.preventDefault();}}inputtypetextvalue{query}onChange{event setQuery(event.target.value)}/button typesubmitSearch/button/form{isError divSomething went wrong .../div}{isLoading ? (divLoading .../div) : (ul{data.hits.map(item (li key{item.objectID}a href{item.url}{item.title}/a/li))}/ul)}/Fragment);
}export default App;通过自定义钩子获取数据。这个钩子自己不知道关于接口的任何信息。他接受所有从外面传入的参数并且只管理必要的状态例如data加载状态和错误状态。他执行请求和返回数据给把它当做自定义获取数据钩子使用的组件。
使用Reducer Hook获取数据
至今我们使用各个state hooks 去管理我们数据的数据获取状态加载和错误状态。然而不知为啥这些状态被自己的state hook管理它们应该属于一起的因为它们关心相同的原因。就像你看到的一样它们都在数据获取函数中使用。它们是一起的一个很好的标志是它们一个接着一个的使用e.g setIsErrorsetIsLoading。让我们使用Reducer Hook结合并替换它们。
一个Reducer Hook 使用一个state对象和一个函数生成一个state对象。这个函数被称为 —— dispatch函数 —— 分发一个action这个action里面有一个type属性和一个可选的payload对象。所有这些信息在真实的reducer函数中被使用去从之前的状态生成一个新的状态所有信息表示为这个action的payload和type。让我们看看在代码中是怎么工作的。
import React, {Fragment,useState,useEffect,// -------------------------------------------------useReducer,// -------------------------------------------------
} from react;
import axios from axios;// -------------------------------------------------
const dataFetchReducer (state, action) {...
};
// -------------------------------------------------const useDataApi (initialUrl, initialData) {const [url, setUrl] useState(initialUrl);// -------------------------------------------------const [state, dispatch] useReducer(dataFetchReducer, {isLoading: false,isError: false,data: initialData,});// -------------------------------------------------...
};这个Reducer Hook使用reducer函数和初始的状态对象作为参数。在我们的例子里data的初始化状态loading和error的初始状态没有改变但是它们替换了单个state hooks通过reducer hook汇总到一个state对象里面管理。
const dataFetchReducer (state, action) {...
};const useDataApi (initialUrl, initialData) {const [url, setUrl] useState(initialUrl);const [state, dispatch] useReducer(dataFetchReducer, {isLoading: false,isError: false,data: initialData,});useEffect(() {const fetchData async () {// -------------------------------------------------dispatch({ type: FETCH_INIT });// -------------------------------------------------try {const result await axios(url);// -------------------------------------------------dispatch({ type: FETCH_SUCCESS, payload: result.data });// -------------------------------------------------} catch (error) {// -------------------------------------------------dispatch({ type: FETCH_FAILURE });// -------------------------------------------------}};fetchData();}, [url]);...
};现在获取数据的时候可以使用dispatch函数发送一个信息给reducer函数。dispatch分发的对象有一个约定的type属性和一个可选的payload属性。这个type告诉reducer函数哪个状态需要改变和reducer可以使用payload去提取一个新的state。毕竟我们只有三个状态改变初始的获取进程。通知成功的数据获取结果。通知失败的数据获取结果。
在自定义钩子的最后这个state就像之前一样被返回出去但是因为我们一整个state对象所以再也没有独立的state了。这样使用useDataApi自定义钩子的人还可以访问到 dataisLoading和 isError。
const useDataApi (initialUrl, initialData) {const [url, setUrl] useState(initialUrl);const [state, dispatch] useReducer(dataFetchReducer, {isLoading: false,isError: false,data: initialData,});...// -------------------------------------------------return [state, setUrl];// -------------------------------------------------
};最后但是很重要的是缺少reducer函数的实现。它需要发出三个不同的状态转换叫作 FETCH_INIT FETCH_SUCCESS 和 FETCH_FAILURE。每个状态转换需要返回一个新的状态对象。让我们看看这个怎么通过switch case实现
const dataFetchReducer (state, action) {// -------------------------------------------------switch (action.type) {case FETCH_INIT:return { ...state };case FETCH_SUCCESS:return { ...state };case FETCH_FAILURE:return { ...state };default:throw new Error();}// -------------------------------------------------
};一个reducer函数可以通过它的arguments访问当前的state和action。现在switch case语句每个状态被转换只返回之前的state。使用解构语句去保证state对象不可变 - 意味着state是不能直接改变的 - 这是最佳实践。现在让我们覆盖一些当前的state需要被返回的属性来改变状态转换的状态
const dataFetchReducer (state, action) {switch (action.type) {case FETCH_INIT:return {...state,// -------------------------------------------------isLoading: true,isError: false// -------------------------------------------------};case FETCH_SUCCESS:return {...state,// -------------------------------------------------isLoading: false,isError: false,data: action.payload,// -------------------------------------------------};case FETCH_FAILURE:return {...state,// -------------------------------------------------isLoading: false,isError: true,// -------------------------------------------------};default:throw new Error();}
};现在每个state的转换。都是通过action的type决定的基于上一个state和可选的payload属性返回一个新的state。例如在请求成功的案例里payload被用于设置新state对象的data。
总之Reducer Hook确保状态管理的这一部分用自己的逻辑封装。通过提供action type和可选的payloads你将总是可以预测变化。另外你将不会再非法的state下运行。例如先前可能搞错了设置isLoading和isError状态变成true。我们在这种情况下怎么展示呢现在每个状态的改变都被reducer 函数变成一个合法的state对象。
在Effect Hook中阻止数据获取
在React中设置未挂载组件的状态是一个常见的问题e.g. 由于通过React Router导航的。我之前写过关于这个问题的文章它描述了在各种场景中如何阻止在未挂载的组件中设置state。让我们看看怎么在我们自定义的数据获取钩子里面阻止状态设置。
const useDataApi (initialUrl, initialData) {const [url, setUrl] useState(initialUrl);const [state, dispatch] useReducer(dataFetchReducer, {isLoading: false,isError: false,data: initialData,});useEffect(() {// -------------------------------------------------let didCancel false;// -------------------------------------------------const fetchData async () {dispatch({ type: FETCH_INIT });try {const result await axios(url);// -------------------------------------------------if (!didCancel) {// -------------------------------------------------dispatch({ type: FETCH_SUCCESS, payload: result.data });// -------------------------------------------------}// -------------------------------------------------} catch (error) {// -------------------------------------------------if (!didCancel) {// -------------------------------------------------dispatch({ type: FETCH_FAILURE });// -------------------------------------------------}// -------------------------------------------------}};fetchData();// -------------------------------------------------return () {didCancel true;};// -------------------------------------------------}, [url]);return [state, setUrl];
};每个Effect Hook都有一个匹配的清除函数它会在组件卸载的时候执行。这个清除函数是一个从hook中返回的函数。在我们的例子里我们使用名字为didCancel的boolean类型的标志让我们数据获取逻辑知道组件状态挂载的/未挂载的。如果组件完成卸载这个标志应该设置为true这个结果会阻止异步获取数据完成之后设置组件的状态 。
注其实数据请求没有被终止 — 可以通过Axios Cancellation实现终止请求的功能—但是状态迁移在组件卸载后不会再执行。由于Axios Concellation在我看来没有更好的API这个boolean值的标志也可以完成阻止设置state的工作。
你已经学会怎么在React获取数据的时候使用React hooks中的state和effets钩子。
如果你对在React类组件函数式组件里面使用render属性和高阶组件获取数据感到好奇查看本篇文章开始处我的其他文章。除此以外我希望这篇文章有助于你学习React Hooks和在真实世界中使用他们。