react-hooks 入门
mport React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} timesp>
<button onClick={() => setCount(count + 1)}>
Click me
button>
div>
);
}
复制代码
useEffect 做了什么?
把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。
useCallback
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const getDownloadFile = useCallback(async () => {
setLoading(true);
try {
const res = await axios.get(API.CUSTOMER.xxx(), {
params: { customer_id: 123 }
});
setData(res.data as any);
} catch (error) {
setError(error);
}
setLoading(false);
}, []);
// 这里的 useEffect() 替代了以前的生命周期做的事情
useEffect(() => {
getDownloadFile();
}, [getDownloadFile]);
我们需要先创建一个 context 对象(React.createContext),接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。
当组件上层最近的 更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value 值。
import { useState } from 'react';
import axios from 'axios';
// 首先定义一下类型
type UseApiResponse = [
{
loading: boolean,
data: null | object | any[],
error: any
},
/**
* 返回一个 promise 对象
*/
(requestData?: any[] | object) => Promise,
];
type UseApiArgs = {
/**
* HTTP Method. 默认 'GET'
*/
method: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE' | 'OPTIONS',
url: string,
/**
* 可选:初始默认值
*/
defaultData?: object | any[],
/**
* 返回数据
*/
bodyData?: object | any[],
};
export const useApi = ({
method = 'GET',
url,
defaultData,
}: UseApiArgs) => {
const [loading, setLoading] = useState(false);
const [data, setData] = useState(defaultData | null)
const [error, setError] = useState(null);
const sendRequest = (requestData?: object | any[]) => {
const requestConfig = {
method,
url,
data: requestData,
};
const axiosConfig = Object.assign({}, requestConfig);
/**
* 返回一个 promise 对象
*/
return new Promise(async (resolve, reject) => {
setLoading(true);
try {
const response = await axios(axiosConfig);
setData(response.data);
resolve(data);
} catch (err) {
setError(error);
reject(err);
} finally {
setLoading(false);
}
});
};
const response: UseApiResponse = [
{
loading,
data,
error
},
sendRequest,
];
return response;
};
export default useApi;
复制代码
上面满足了基本的调用server api 的需求,但是远远是不能满足一些复杂的情况的,我们下面来升级一下我们扥 hooks,增加状态码,增加加载状态,主动触发 request 的需求等等
import { createContext, useState, useEffect, useContext } from 'react';
import axios from 'axios';
/**
* ApiContext 这里可以配置全局的 config.
*/
export const ApiContext = createContext({});
// 首先定义一下类型
type UseApiResponse = [
{
loading: boolean,
data: null | object | any[],
error: Error || null,
/**
* The HTTP status number
*/
status: number,
/**
* True unless and until the request has been triggered at least once
*/
initialLoad: boolean,
/**
* pending 状态
*/
pendingOrLoading: boolean,
/**
* axios 对象
*/
responseObj: object,
},
/**
* 返回一个 promise 对象
*/
(requestData?: any[] | object) => Promise,
];
type UseApiArgs = {
/**
* HTTP Method. 默认 'GET'
*/
method: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE' | 'OPTIONS',
url: string,
/**
* 可选:初始默认值
*/
defaultData?: object | any[],
/**
* 返回数据
*/
bodyData?: object | any[],
/**
* 可选 : 如果你想主动调用 request, 设置为 true
*/
autoTrigger?: boolean,
};
export const useApi = ({
method = 'GET',
autoTrigger = true,
url,
defaultData,
bodyData,
}: UseApiArgs) => {
const [initialLoad, setInitialLoad] = useState(true);
const [loading, setLoading] = useState(false);
const [data, setData] = useState(defaultData || null)
const [error, setError] = useState(null);
const [status, setStatus] = useState();
const [responseObj, setResponseObj] = useState();
/**
* 你可以使用自定义的 api 来替代 Axios config
*/
const globalConfig = useContext(ApiContext);
const sendRequest = (requestData?: object | any[]) => {
const requestConfig = {
method,
url,
data: requestData,
};
const axiosConfig = Object.assign({}, globalConfig, requestConfig);
/**
* 返回一个 promise 对象
*/
return new Promise(async (resolve, reject) => {
setLoading(true);
try {
const response = await axios(axiosConfig);
setResponseObj(response);
setData(response.data);
setStatus(response.status);
resolve(data);
} catch (err) {
setError(error);
reject(err);
} finally {
setLoading(false);
if (initialLoad) setInitialLoad(false);
}
});
};
/**
* 如果设置了自动触发这个参数,这里需要特殊处理一下,检查一下 initiaload 加载状态是否完成,然后处理 'POST', 'PATCH', 'PUT'
*/
if (autoTrigger) {
useEffect(() => {
if (initialLoad) {
/**
* Include body data if method allows
*/
if (['POST', 'PATCH', 'PUT'].includes(method)) {
sendRequest(bodyData);
} else sendRequest();
}
}, []);
}
const response: UseApiResponse = [
{
loading,
data,
error,
status,
initialLoad,
pendingOrLoading: initialLoad || loading,
responseObj,
},
sendRequest,
];
return response;
};
export default useApi;
复制代码
import React, { useEffect, useRef } from 'react';
import useApi, { ApiContext } from 'use-http-api';
const UserList = () => {
const [{ loading, data }, getUsers] = useApi({
url: 'https://reqres.in/api/users',
defaultData: { data: [] },
});
return (
<div>
{loading ? (
'Loading...'
) : (
<ol>
{data.data.map(user => (
<li>{user.email}li>
))}
ol>
)}
<button onClick={() => getUsers()}>Updatebutton>
div>
);
};
复制代码