最近項目 升級了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>
);
};
複製代碼