使用 react hooks 优雅的获取数据
写在最前面
适用于 react,es6使用者,react hooks 初学者。
本文主要写关于怎么使用
state
和
effect
hooks 来优雅的获取列表数据。
当然你需要先了解一下 react hooks 的新特性
使用 hook 获取数据
1、useState的使用
import React, { useState } from 'react';
function App() {
const [data, setData] = useState({ hits: [] });
return (
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}a>
export default App;
复制代码
复制
state
, hooks 主动去回调
userState
方法,把
data
存储在
state
中。
2、Axios 的使用(useEffect的使用)
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?query=redux',
// 使用 useEffect 的时候,我们主动设置 `state` ,存储 `setData`
setData(result.data);
return (
{data.hits.map(item => (
复制
))}
export default App;
当你运行上面的程序的时候会发现有 bug ,这是为什么啦?因为当我们在获取数据后存储数据到 state 中的时候,我们的组件会随之更新,然后
effect
会再次运行一次。然后我们会又获取一次
data
。
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..
怎么避免上面的问题啦?
我们的目的是只在组件加载完成的时候获取数据
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function App() {
const [data, setData] = useState({ hits: [] });
// 单独拆分 fetchData
const fetchData = async () => {
const result = await axios(
'http://hn.algolia.com/api/v1/search?query=redux',
setData(result.data);
// 单独拆分 fetchData 的原因是: 上面的 waring 部分,不推荐把 async 写在 effect 中
useEffect(() => {
fetchData();
}, []);
// 这里的第二个参数: 是 hooks 来观测数值的变化
// 这里添加 [],当我们的组件更新的时候回去观测 effect 的值是否有变化,这里添加空 [] ,是为了防止 hooks 再一次运行。
return (
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}a>
export default App;
复制代码
复制
function App() {
// In order to prevent the default behavior,为了防止form 的默认行为,我们建议单独把 doGet 方法拆分出来写。而不是直接写在 form
的 onchange 方法中
const doGet = event => {
setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`);
event.preventDefault();
return (
<Fragment>
<form onSubmit={doGet}>
<input
type="text"
value={query}
onChange={event => setQuery(event.target.value)}
<button type="submit">Searchbutton>
{isError && <div>Something went wrong ...div>}
Fragment>
复制代码
复制
4、怎么定制一个数据获取的 hook?
我们当然可以根据自己的情况定制一个 hook 来获取我们的数据,这里需要处理 loading ,error 情况,数据来源等。
// 做一个新闻的数据获取的 API
const useHackerNewsApi = () => {
const [data, setData] = useState({ hits: [] });
const [url, setUrl] = useState(
'http://hn.algolia.com/api/v1/search?query=redux',
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const fetchData = async () => {
setIsError(false);
setIsLoading(true);
try {
const result = await axios(url);
setData(result.data);
} catch (error) {
setIsError(true);
setIsLoading(false);
useEffect(() => {
fetchData();
}, [url]);
const doGet = event => {
setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`);
event.preventDefault();
return { data, isLoading, isError, doGet };
复制代码
复制
// 直接调用即可
function App() {
const [query, setQuery] = useState('redux');
const { data, isLoading, isError, doGet } = useHackerNewsApi();
return (
<Fragment>
Fragment>
复制代码
复制
进一步的定制
API
的
url
const useHackerNewsApi = () => {
useEffect(
const doGet = (event, url) => {
setUrl(url);
event.preventDefault();
return { data, isLoading, isError, doGet };
function App() {
const [query, setQuery] = useState('redux');
const { data, isLoading, isError, doGet } = useHackerNewsApi();
return (
<Fragment>
onSubmit={event =>
doGet(
event,
`http://hn.algolia.com/api/v1/search?query=${query}`,
<input
type="text"
value={query}
onChange={event => setQuery(event.target.value)}
<button type="submit">Searchbutton>
Fragment>
复制代码
复制
定制
state
的 初始化data
import React, { Fragment, useState, useEffect } from 'react';
import axios from 'axios';
// 定制 initialUrl 和 initialData
const useDataApi = (initialUrl, initialData) => {
const [data, setData] = useState(initialData);
const [url, setUrl] = useState(initialUrl);
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const fetchData = async () => {
setIsError(false);
setIsLoading(true);
try {
const result = await axios(url);
setData(result.data);
} catch (error) {
setIsError(true);
setIsLoading(false);
useEffect(() => {
fetchData();
}, [url]);
const doGet = (event, url) => {
setUrl(url);
event.preventDefault();
return { data, isLoading, isError, doGet };
function App() {
const [query, setQuery] = useState('redux');
const { data, isLoading, isError, doGet } = useDataApi(
'http://hn.algolia.com/api/v1/search?query=redux',
{ hits: [] },
return (
<Fragment>
onSubmit={event =>
doGet(
event,
`http://hn.algolia.com/api/v1/search?query=${query}`,
<input
type="text"
value={query}
onChange={event => setQuery(event.target.value)}
<button type="submit">Searchbutton>
{isError && <div>Something went wrong ...div>}
{isLoading ? (
<div>Loading ...div>
) : (
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}a>
Fragment>