最近项目 升级了react 16.8+,接入了 hooks,这里学习一下最基础的几个官方 hookshtml
下面是官网文档的连接,基础知识掌握不牢靠的朋友能够再看看,官网的文档能够说是很是完整和浅出了。个人文章主要讨论具体的几个 hooks 的具体使用场景。react
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} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div>
);
}
复制代码
useEffect 作了什么?git
把内联回调函数及依赖项数组做为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。github
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 的当前值。axios
当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value 值。api
下面代码使用了 TypeScript数组
example: codesandbox.io/s/fragrant-…promise
简单版less
import { useState } from 'react';
import axios from 'axios';
// 首先定义一下类型
type UseApiResponse = [
{
loading: boolean,
data: null | object | any[],
error: any
},
/** * 返回一个 promise 对象 */
(requestData?: any[] | object) => Promise<any>,
];
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<any>,
];
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()}>Update</button> </div>
);
};
复制代码