ReactJS Typescript 如何从 axios 拦截器触发 redux 调度事件

问题描述 投票:0回答:1

我是 ReactJS 打字稿的新手,我想在任何 api 被调用时(之前和之后)使用 axios 拦截器调用 redux 调度事件。 这是我的代码。

Codesandbax 存储库

应用程序.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>&nbsp;</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 响应存储在状态中。

提前谢谢您。

reactjs typescript redux axios
1个回答
0
投票

经过大量研究,我终于弄清楚了,并且一些文件几乎没有变化。

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;
};
© www.soinside.com 2019 - 2024. All rights reserved.