【问题标题】:Migrating from Redux to Redux toolkit从 Redux 迁移到 Redux 工具包
【发布时间】:2021-01-05 16:17:58
【问题描述】:

我正在慢慢地从 Redux 迁移到 Redux 工具包。我还是很新,但我有这个登录操作功能。如何翻译下面的旧功能我需要createAsyncThunk 来实现吗?

export const login = (email, password) => (dispatch) => {
  dispatch(requestLogin());
  firebase
    .auth()
    .signInWithEmailAndPassword(email, password)
    .then((user) => {
      dispatch(responseLogin(user));
    })
    .catch((error) => {
      dispatch(loginError());
    });
};

我的授权切片看起来像这样:

const authSlice = createSlice({
  name: "authSlice",
  initialState: {
    isLoggingIn: false,
    isLoggingOut: false,
    isVerifying: false,
    loginError: false,
    logoutError: false,
    isAuthenticated: false,
    user: {},
  },
  reducers: {
    signInWithEmail: (state, action) => {
      const { email, password } = action.payload;
      firebase
        .auth()
        .signInWithEmailAndPassword(email, password)
        .then((response) => {
          const {
            uid,
            email,
            emailVerified,
            phoneNumber,
            password,
            displayName,
            photoURL,
          } = response.user;
        })
        .catch((error) => {
          console.log(error);
        });
    },
  },
  extraReducers: {},
});

【问题讨论】:

  • 如果您需要在动作创建器中使用dispatch,可以使用createAsyncThunk。你能在你的项目中使用async/await吗?
  • 是的,因为马克已经提供了答案。你能告诉我如何调度我的行动吗?

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


【解决方案1】:

你展示的reducer是非常错误的。 reducer 必须从不异步执行任何事情

你不需要createAsyncThunk,但如果你使用它,它会是这样的:

export const login = createAsyncThunk(
  'login',
  ({email, password}) => firebase.auth().signInWithEmailAndPassword(email, password)
);

const authSlice = createSlice({
  name: "authSlice",
  initialState: {
    isLoggingIn: false,
    isLoggingOut: false,
    isVerifying: false,
    loginError: false,
    logoutError: false,
    isAuthenticated: false,
    user: {},
  },
  reducers: {
    /* any other state updates here */
  },
  extraReducers: (builder) => {
    builder.addCase(login.pending, (state, action) => {
      // mark something as loading here
    }

    builder.addCase(login.fulfilled, (state, action) => {
      // mark request as complete and save results
    }
  }
});

请注意,createAsyncThunk 只允许将一个参数传递给 thunk 动作创建者,因此它现在必须是具有两个字段的对象,而不是单独的参数。

【讨论】:

  • 感谢您的回答。最初我的减速器中有[login.pending]: (state) => {},但这不起作用。是否需要为我的所有 asyncThunk 包装在 Builder 中?
  • 您可以使用 extraReducers 中的语法来响应切片外部定义的操作,但不能在 reducers. 内部定义。但是,由于该语法不适用于 TypeScript,我们'现在重新鼓励使用“builder”语法作为首选方法。
  • 如何获得 Firebase 参考?
【解决方案2】:

让我们创建一个productSlice.js

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

export const fetchProducts = createAsyncThunk(
  "products/fetchProducts", async (_, thunkAPI) => {
     try {
        const response = await fetch(`url`); //where you want to fetch data
        return await response.json();
      } catch (error) {
         return thunkAPI.rejectWithValue({ error: error.message });
      }
});

const productsSlice = createSlice({
   name: "products",
   initialState: {
      products: [],
      loading: "idle",
      error: "",
   },
   reducers: {},
   extraReducers: (builder) => {
      builder.addCase(fetchProducts.pending, (state) => {
        state. products = [];
          state.loading = "loading";
      });
      builder.addCase(
         fetchProducts.fulfilled, (state, { payload }) => {
            state. products = payload;
            state.loading = "loaded";
      });
      builder.addCase(
        fetchProducts.rejected,(state, action) => {
            state.loading = "error";
            state.error = action.error.message;
      });
   }
});


export const selectProducts = createSelector(
  (state) => ({
     products: state.products,
     loading: state.products.loading,
  }), (state) =>  state
);
export default productsSlice;

在您的store.js 中添加productsSlice: productsSlice.reducer 到店外减速器中。

然后在组件中使用添加这些代码......我也更喜欢使用钩子

import { useSelector, useDispatch } from "react-redux";

import { fetchProducts,selectProducts,} from "path/productSlice.js";

然后最后一部分像这样在你的主管内部调用这些方法

const dispatch = useDispatch();
const { products } = useSelector(selectProducts);
React.useEffect(() => {
   dispatch(fetchProducts());
}, [dispatch]); 

最后,您可以在组件中以products 的身份访问数据。

【讨论】:

    猜你喜欢
    • 2021-08-08
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 2017-06-01
    • 2021-06-03
    • 2021-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多