【问题标题】:How to refactor duplicate code in Redux-Toolkit, createAsyncThunk and extraReducers?如何重构 Redux-Toolkit、createAsyncThunk 和 extraReducers 中的重复代码?
【发布时间】:2021-09-11 23:27:29
【问题描述】:

我第一次在我的 React 项目中使用 Redux。我在此处添加的代码用于基于 cookie 的身份验证。我担心这里的一切都是正确的格式。这里似乎有很多重复的代码。特别是对于 createSlice 部分中的待处理和拒绝状态。如何重构此代码以及在这种情况下正确的编码风格是什么?

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";

import API from "../API";

// Register user:

export const signup = createAsyncThunk(
  "user/signup",
  async (userInfo, { rejectWithValue }) => {
    try {
      const { data } = await API.post("/signup", userInfo);
      return data;
    } catch (error) {
      return rejectWithValue(error.response.data);
    }
  }
);

// Login:
export const login = createAsyncThunk(
  "user/login",
  async (loginInfo, { rejectWithValue }) => {
    try {
      const { data } = await API.post("/login", loginInfo);
      return data;
    } catch (error) {
      return rejectWithValue(error.response.data);
    }
  }
);

// Logout:
export const logout = createAsyncThunk(
  "user/logout",
  async (args, { rejectWithValue }) => {
    try {
      const { data } = await API.get("/logout");
      return data;
    } catch (error) {
      return rejectWithValue(error.response.data);
    }
  }
);

// Chek-Auth:
export const isAuthenticated = createAsyncThunk(
  "user/isAuthenticated",
  async (args, { rejectWithValue }) => {
    try {
      const { data } = await API.get("/check-auth");
      return data;
    } catch (error) {
      return rejectWithValue(error.response.data);
    }
  }
);

// createSlice portion is here:
export const userSlice = createSlice({
  name: "user",
  initialState: {
    loading: true,
    isLoggedIn: false,
    message: "",
    user: null,
    error: null,
  },
  reducers: {},
  extraReducers: {
    [signup.pending]: (state, action) => {
      state.loading = true;
    },
    [signup.fulfilled]: (state, action) => {
      state.loading = false;
      state.isLoggedIn = true;
      state.message = action.payload.message;
      state.user = action.payload.user;
      state.error = null;
    },
    [signup.rejected]: (state, action) => {
      state.loading = false;
      state.error = action.payload || action.error;
    },
    [login.pending]: (state, action) => {
      state.loading = true;
    },
    [login.fulfilled]: (state, action) => {
      state.loading = false;
      state.isLoggedIn = true;
      state.message = action.payload.message;
      state.user = action.payload.user;
      state.error = null;
    },
    [login.rejected]: (state, action) => {
      state.loading = false;
      state.error = action.payload || action.error;
    },
    [logout.pending]: (state, action) => {
      state.loading = true;
    },
    [logout.fulfilled]: (state, action) => {
      state.loading = false;
      state.isLoggedIn = false;
      state.message = action.payload.message;
      state.user = null;
    },
    [logout.rejected]: (state, action) => {
      state.loading = false;
      state.error = action.payload || action.error;
    },
    [isAuthenticated.pending]: (state, action) => {
      state.loading = true;
    },
    [isAuthenticated.fulfilled]: (state, action) => {
      state.loading = false;
      state.isLoggedIn = true;
      state.message = action.payload.message;
      state.user = action.payload.user;
    },
    [isAuthenticated.rejected]: (state, action) => {
      state.loading = false;
      state.error = action.payload || action.error;
    },
  },
});

// export const {  } = userSlice.actions;

export default userSlice.reducer;

【问题讨论】:

    标签: reactjs express redux react-redux redux-toolkit


    【解决方案1】:

    我们通常建议使用构建器表示法,而不是对象表示法。这使得这样的事情更容易:

    extraReducers: builder => {
      for (const thunk in [signup, login, logout, isAuthenticated]) {
        builder.addCase(thunk.pending, (state) => { state.loading = true })
        builder.addCase(thunk.rejected, (state, action) => { 
          state.loading = false;
          state.error = action.payload || action.error;
        })
      }
    }
    

    请记住,尽管像您在此处那样将许多异步操作置于同一状态,共享加载状态,但可能会导致竞争条件。

    一般来说,对于 api 缓存的东西,你应该看看 Redux Toolkit 的 Api 缓存抽象,RTK-Query: https://redux-toolkit.js.org/rtk-query/overview

    【讨论】:

    • 您的回答很有帮助,但如果您也能显示 thunk.fulfilled 的代码,那就太好了。我们需要对异步 crud 操作使用相同的状态。您是否建议在这种情况下使用这种方法或任何其他替代方式?
    • 我已经向您展示了如何减少通用代码的示例,您可能仍然需要手动编写其余部分,因为它不同。但一般来说,我会为每个正在进行的请求使用不同的加载变量(即使它抽象代码可能会变得更加困难)。再说一遍:我可能不会写任何代码,而是使用 RTK-Query。
    猜你喜欢
    • 2021-09-17
    • 2021-08-23
    • 1970-01-01
    • 2021-04-23
    • 2020-09-26
    • 1970-01-01
    • 2020-09-13
    • 2023-01-19
    • 2021-05-01
    相关资源
    最近更新 更多