背景
其实网上关于@reduxjs/toolkit的介绍很多了,但是我发现很少有关于createApi这个方法介绍的,这个功能却又特别强大,于是写下这篇文章
正文开始
import { configureStore } from "@reduxjs/toolkit";
import globalReducer from "./globalReducer";
const store = configureStore({
reducer: {
globalReducer,
},
});
export default store;
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
type Props = {
userInfo: {
routerList: string[];
name: string;
loading: boolean;
};
};
const initialState: Props = {
userInfo: {
routerList: [],
name: "",
loading: true,
},
};
const getUserInfo = (params: any): Promise<any> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
routes: ["home", "detail", "list", "404", "home/detail"],
userName: "jianjian",
});
}, 1000);
});
};
export const fetchUserInfo = createAsyncThunk<any>(
"globalReducer/getUsreInfo",
async (params, thunkAPI) => {
const data = await getRoutes(params);
return data;
}
);
const globalReducer = createSlice({
name: "globalReducer",
initialState,
reducers: {
add() {
console.log(111);
}
},
extraReducers: (builder) => {
builder.addCase(fetchUserInfo.pending, (state) => {
state.userInfo.loading = true;
});
builder.addCase(fetchUserInfo.fulfilled, (state, action) => {
state.userInfo.loading = false;
state.userInfo.routerList = action.payload.routes;
state.userInfo.name = action.payload.name;
});
},
});
const { actions, reducer } = globalReducer
export default globalReducer.reducer;
import { AppDispatch, RootState } from "../store";
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
import { useAppSelector } from "../hooks";
const Demo = () => {
const {
userInfo: { routerList, loading },
} = useAppSelector((state) => state.globalReducer);
return <>{loading ? <div>loading...</div> : <div>403......</div>}</>;
};
export default Demo;
我们看到以上处理异步情况需要做的工作
1 通过 createAsyncThunk 创建一个promise的reducer方法
2 在extraReducers中处理异步请求的情况 (pending, fulfilled, reject)
3 根据不同的情况修改initialState像loading 请求的数据 错误信息等等...
4 然后在组件中 去dispatch我们通过createAsyncThunk创建的任务
5 然后在组件中通过 useSelectore 去获取我们获取的数据
以上很多工作还是需要我们手动去处理和判断,
而且如果接口多的情况下很多工作都是重复的(最基本的像loading, 数据,请求状况),
那我们能不能把这些重复的工作省略掉呢? createApi就可以!!!
通过createApi去改造我们上面的异步请求
import { configureStore } from "@reduxjs/toolkit";
import globalReducer from "./globalReducer";
const store = configureStore({
reducer: {
[globalReducer.reducerPath]: globalReducer.reducer
},
});
export default store;
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
const globalReducer = createApi({
reducerPath: 'globalReducer',
baseQuery: fetchBaseQuery({
baseUrl: "http://localhost:8080",
prepareHeaders: (headers, { getState }) => {
const token = '你的token';
if (token) {
headers.set("authorization", `Bearer ${token}`);
}
return headers;
},
}),
endpoints: (builder) => {
return {
getTodos: builder.query({query: (id) => ({
method: 'GET',
url: `/todos/detail/${id}`,
params: {
name: 'xxxx'
}
})}),
}
}
})
export default globalReducer;
import globalReducer from '../globalReducer'
const Demo = () => {
const { isLoading, data, isError, isSuccess } = globalReducer.useGetTodosQuery(1)
return <>{isLoading ? <div>loading...</div> : <div>403......</div>}</>;
1 通过createApi 以上三步骤就完成了一个异步请求
2 我们可以对比一下
3 useGetTodosQuery 是根据 第二步中的 endpoints下的 getTodos方法名自动生成的hook,
4 如果我们方法名叫做 getAdd, 那么讲自生成一个useGetAddQuery的hook
5 (明白了嘛,自动生成的,你也可以把useGetTodosQuery写成todoApi.endpoints.getTodos)
6 globalReducer.useGetTodosQuery(1) 表示我们调用 getTodos这个接口并且传入参数1
7 返回值中,已经帮我们处理好了loading,数据,错误等等 类似ahooks中的useRequest
7 第二步的请求是toolkit内置的fetchBaseQuery方法,有时候我们想用自己的或者基于axios封装的怎么办呢?往下看
createApi采用axios封装请求方法
import type { BaseQueryFn } from "@reduxjs/toolkit/query";
import axios from "axios";
import type { AxiosRequestConfig, AxiosError } from "axios";
const axiosBaseQuery =
(
{ baseUrl }: { baseUrl: string } = { baseUrl: "" }
): BaseQueryFn<
{
url: string;
method: AxiosRequestConfig["method"];
data?: AxiosRequestConfig["data"];
params?: AxiosRequestConfig["params"];
},
unknown,
unknown
> =>
async ({ url, method, data, params }) => {
try {
const result = await axios({ url: baseUrl + url, method, data, params });
return { data: result.data };
} catch (axiosError) {
let err = axiosError as AxiosError;
return {
error: {
status: err.response?.status,
data: err.response?.data || err.message,
},
};
}
};
const globalReducer = createApi({
reducerPath: 'globalReducer',
baseQuery: axiosBaseQuery({ baseUrl: 'http://localhost:8080' }),
endpoints: (builder) => {
return {
getTodos: builder.query({query: (id) => ({
method: 'POST',
url: `/todos/detail/${id}`,
params: {
name: 'jiajian'
}
})}),
getList: builder.query({
query: () => `/todos/list`
}),
}
}
})
over,希望大家有所收获~