我是 ReactJS 打字稿的新手,我想在任何 api 被调用时(之前和之后)使用 axios 拦截器调用 redux 调度事件。 这是我的代码。
应用程序.tsx
import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";
import { Employee } from "./Pages/Employee/Employee";
import { Provider } from "react-redux";
import store from "./Redux/store";
function App() {
return (
<Provider store={store}>
<Employee />
</Provider>
);
}
export default App;
员工.tsx
import { useEffect, useState } from "react";
import { IEmployeeList } from "../../Models/Employee";
import { EmployeeList } from "./EmployeeList";
import { EmployeeService } from "./EmployeeServices";
import Button from "react-bootstrap/Button";
import { useDispatch, useSelector } from "react-redux";
import { trackRefreshCount } from "../../Redux/RefreshCount/slice";
export const Employee: React.FC = () => {
const getEmployeesList = EmployeeService();
const [empTblList, setEmpTblList] = useState<IEmployeeList[]>([]);
const dispatch = useDispatch();
const { loader, trackRefreshCountSlice }: any = useSelector(
(state: any) => state
);
useEffect(() => {
SetEmployeeList();
}, []);
const SetEmployeeList = async () => {
const data = await getEmployeesList("");
setEmpTblList(data);
};
return (
<div>
<Button
disabled={loader.isLoading}
variant="primary"
onClick={() => {
dispatch(trackRefreshCount());
SetEmployeeList();
}}
>
Refresh ({trackRefreshCountSlice.refreshCount})
</Button>
<EmployeeList EmpTableList={empTblList} />
</div>
);
};
员工列表.tsx
import { IEmployeeList } from "../../Models/Employee";
import Table from "react-bootstrap/Table";
import { useSelector } from "react-redux";
import SkeletonTable from "../../Component/Skeleton/SkeletonTable";
import { useEffect } from "react";
export const EmployeeList = (props: { EmpTableList: any }) => {
const { EmpTableList } = props;
const { loader } = useSelector((state: any) => state);
useEffect(() => {
console.log("loader :: ", loader);
}, []);
return (
<div className="table-container">
<Table responsive>
<thead>
<tr>
<th>Name</th>
<th>Active</th>
<th>Birthday</th>
<th></th>
</tr>
</thead>
<tbody>
{loader.isLoading ? (
<SkeletonTable Column={3} Row={10} />
) : (
EmpTableList?.map((d: IEmployeeList, index: number) => {
return (
<tr key={index}>
<td>{d.name}</td>
<td>{d.isActive ? "Active" : "Inactive"}</td>
<td>{d.birthday}</td>
<td> </td>
</tr>
);
})
)}
</tbody>
</Table>
</div>
);
};
EmployeeServices.ts
import API from "../../Helpers/HttpClient";
import { showLoader, hideLoader } from "../../Redux/Loader/slice";
import { useDispatch } from "react-redux";
export const EmployeeService = () => {
const dispatch = useDispatch();
const getEmployeesList: any = async (loader: string) => {
try {
//dispatch(showLoader()); // Here showLoader is working fine
const response = await API.get("uow", {
headers: { custom_loader: "SHOW_LOADER" },
});
//dispatch(hideLoader()); // Here hideLoader is working fine
return response.data;
} catch (error) {
console.log(error);
// dispatch(hideLoader()); // Here hideLoader is working fine
}
};
return getEmployeesList;
};
src -> Redux -> 加载器 -> slice.ts
import { createSlice } from "@reduxjs/toolkit";
export interface LoaderState {
isLoading: boolean;
}
const initialState: LoaderState = {
isLoading: false,
};
export const loadSlice = createSlice({
name: "loaderSlice",
initialState,
reducers: {
showLoader: (state): void => {
state.isLoading = true;
},
hideLoader: (state): void => {
state.isLoading = false;
},
},
});
export const { showLoader, hideLoader } = loadSlice.actions;
export default loadSlice.reducer;
src->Redux->RefreshCount->slice.ts
import { createSlice } from "@reduxjs/toolkit";
export interface LoaderState {
refreshCount: number;
}
const initialState: LoaderState = {
refreshCount: 0,
};
export const trackRefreshCountSlice = createSlice({
name: "refreshCountSlice",
initialState,
reducers: {
trackRefreshCount: (state): void => {
state.refreshCount += 1;
},
},
});
export const { trackRefreshCount } = trackRefreshCountSlice.actions;
export default trackRefreshCountSlice.reducer;
src -> Redux -> store.ts
import { configureStore } from "@reduxjs/toolkit";
import loaderReducer from "./Loader/slice";
import trackRefreshCountSlice from "./RefreshCount/slice";
const store = configureStore({
reducer: {
loader: loaderReducer,
trackRefreshCountSlice: trackRefreshCountSlice,
},
});
export default store;
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
src -> 助手 -> HttpClients.ts
import axios from "axios";
import { setupInterceptorsTo } from "./AxiosInterceptors";
let baseURL = "https://localhost:7131/api/";
const axiosClient = setupInterceptorsTo(
axios.create({
baseURL,
})
);
export default axiosClient;
src -> 助手 -> AxiosInterceptors.ts
import {
AxiosError,
AxiosInstance,
AxiosResponse,
InternalAxiosRequestConfig,
} from "axios";
import { ShowLoader, HideLoader } from "../Redux/DispatchActions";
const onRequest = (
config: InternalAxiosRequestConfig
): InternalAxiosRequestConfig => {
debugger;
switch (config.headers.custom_loader) {
case "SHOW_LOADER":
ShowLoader(); --> This lines throws an error
}
console.info(`[request] [${JSON.stringify(config)}]`);
return config;
};
const onRequestError = (error: AxiosError): Promise<AxiosError> => {
console.error(`[request error] [${JSON.stringify(error)}]`);
return Promise.reject(error);
};
const onResponse = (response: AxiosResponse): AxiosResponse => {
console.info(`[response] [${JSON.stringify(response)}]`);
return response;
};
const onResponseError = (error: AxiosError): Promise<AxiosError> => {
console.error(`[response error] [${JSON.stringify(error)}]`);
return Promise.reject(error);
};
export function setupInterceptorsTo(
axiosInstance: AxiosInstance
): AxiosInstance {
axiosInstance.interceptors.request.use(onRequest, onRequestError);
axiosInstance.interceptors.response.use(onResponse, onResponseError);
return axiosInstance;
}
src -> Redux -> DispatchActions.ts
import { useDispatch } from "react-redux";
import { showLoader, hideLoader } from "./Loader/slice";
export const ShowLoader = () => {
debugger;
const dispatch = useDispatch();
dispatch(showLoader());
return null;
};
export const HideLoader = () => {
const dispatch = useDispatch();
dispatch(hideLoader());
};
src -> 模型 -> 员工
export interface IEmployee {
employeeId: number;
name: string;
isActive: boolean;
birthday: any;
}
export interface IEmployeeList extends IEmployee {}
src -> 模型 -> Loader.ts
export interface LoaderModel {
readonly isLoading: boolean;
}
到目前为止,redux 调度程序正在按预期工作,但我想在拦截器中移动调度事件,因此每当调用任何 api 时,我都会通过 api 传递一些参数,以便拦截器将相应地调用调度事件,从而执行调度事件触发器在调用 api 之前,如果 api 再次响应失败/成功,将相应地调用调度。 注意:我不想在 redux 状态的任何地方存储 api 响应,这就是我不使用 thunk 的原因。如果您有任何其他方式使用 thunk 而不将 api 响应存储在状态中。
提前谢谢您。
经过大量研究,我终于弄清楚了,并且一些文件几乎没有变化。
AxiosInterceptors.ts
import axios from "axios";
import { useDispatch } from "react-redux";
const useAxios = () => {
const dispatch = useDispatch();
const axiosClient = axios.create({
baseURL: "https://localhost:7131/api/",
});
axiosClient.interceptors.response.use(
(response) => {
dispatch({ type: response.config.headers.custom_loader });
return response;
},
(error) => {
dispatch({ type: error.config.headers.custom_loader });
return Promise.reject(error);
}
);
axiosClient.interceptors.request.use(
(config) => {
dispatch({ type: config.headers.custom_loader });
config.headers["Content-Type"] = "application/json";
return config;
},
(error) => {
Promise.reject(error);
}
);
return axiosClient;
};
export default useAxios;
HttpClients.ts
import useAxios from "./AxiosInterceptors";
import CONSTANT_LOAD from "./LoadingConstants";
export const HttpGet = () => {
const axiosClient = useAxios();
const get: any = async (url: string, loader: string) => {
try {
if (typeof loader !== "string" || !loader) {
loader = CONSTANT_LOAD.TOGGLE_FULL_SCREEN_LOADER;
}
const response = await axiosClient.get(url, {
headers: { custom_loader: loader },
});
return response;
} catch (error) {
console.log(error);
}
};
return get;
};
添加新文件:LoadingConstants.ts
const CONSTANT_LOAD = {
TOGGLE_FULL_SCREEN_LOADER: "loaderSlice/toggleFullScreenLoader",
TOGGLE_EMPLOYEE_LIST_LOADER: "employeeLoaderSlice/toggleEmployeeListLoader",
};
export default CONSTANT_LOAD;
EmployeeServices.ts
import { HttpGet } from "../../Helpers/HttpClient";
import CONSTANT_LOAD from "../../Helpers/LoadingConstants";
export const EmployeeService = () => {
const httpGet = HttpGet();
const getEmployeesList: any = async () => {
try {
const response = await httpGet(
"uow",
CONSTANT_LOAD.TOGGLE_EMPLOYEE_LIST_LOADER
);
return response.data;
} catch (error) {
console.log(error);
}
};
return getEmployeesList;
};