javascript - Redux 工具包 createAsyncThunk 问题 : state updates after async dispatch call?

标签 javascript reactjs redux react-redux redux-toolkit

我现在正在学习 Redux Thunk。我尝试使用 Redux Toolkit 中的 createAsyncThunk 来处理用户登录,但遇到了一些问题。我创建了一个demo这里('[email protected]'+任意密码=>成功,其他组合=>拒绝)。

我创建了一个模式,供用户使用 reactstrap 输入电子邮件和密码。单击登录按钮,然后您将看到表单。

这是我的UserSlice.js 文件:

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

export const login = createAsyncThunk(
    "user/login",
    async (userInfo, { rejectWithValue }) => {
        try {
            const response = await loginFeedback(userInfo);

            return response.data;
        } catch (err) {
            return rejectWithValue(err);
        }
    }
);

const initialState = {
    isAuthenticated: false,
    isLoading: false,
    user: null,
    error: null,
};

const userSlice = createSlice({
    name: "users",
    initialState,
    reducers: {},
    extraReducers: {
        [login.pending]: (state, action) => {
            state.isLoading = true;
            state.isAuthenticated = false;

        },
        [login.fulfilled]: (state, action) => {
            state.isLoading = false;
            state.isAuthenticated = true;
            state.user = action.payload;
        },
        [login.rejected]: (state, action) => {
            state.isLoading = false;
            state.isAuthenticated = false;
            state.user = [];
            state.error = action.payload.message;
        },
    },
});

export default userSlice.reducer;

因此,在我的 LoginModal.js 文件中,当单击“登录”按钮时,它将启动表单提交函数 handleSubmit():

 const handleSubmit = (e) => {
        e.preventDefault();

        dispatch(login({ email, password }))
        // something else....
}

因此,在 UserSlice.js 中,login 函数将处理异步调用以获取数据,因为我使用了 createAsyncThunkcreateAsyncThunk 将创建三个操作:pendingfulfilledrejected。我在 userSliceextraReducers 中相应地定义了操作。

// userSlice.js
        [login.pending]: (state, action) => {
            state.isLoading = true;
            state.isAuthenticated = false;

        },
        [login.fulfilled]: (state, action) => {
            state.isLoading = false;
            state.isAuthenticated = true;
            state.user = action.payload;
        },
        [login.rejected]: (state, action) => {
            state.isLoading = false;
            state.isAuthenticated = false;
            state.user = [];
            state.error = action.payload.message;
        },

因此,如果loginFeedback成功,则isAuthenticated状态应设置为true,如果调用被拒绝,则应设置为false 我们将在表单中显示一条错误消息。

在我的LoginModal.js中,如果用户身份验证成功,我想关闭模式,如果失败,则显示错误消息。为了像正常的 Promise 内容一样对待操作,我在 Redux Toolkits ( here ) 中找到了这个:

The thunks generated by createAsyncThunk will always return a resolved promise with either the fulfilled action object or rejected action object inside, as appropriate.

The calling logic may wish to treat these actions as if they were the original promise contents. Redux Toolkit exports an unwrapResult function that can be used to extract the payload of a fulfilled action or to throw either the error or, if available, payload created by rejectWithValue from a rejected action.

所以我将我的 handleSubmit 函数编写为:

 const handleSubmit = (e) => {
        e.preventDefault();

        dispatch(login({ email, password }))
            .then(unwrapResult)
            .then(() => {
                if (isAuthenticated && modal) {
                    setEmail("");
                    setPassword("");
                    toggle();
                }
            })
            .catch((error) => {
                setHasError(true);
            });
    };

我们首先unwrapResult,然后如果promise返回成功并且状态isAuthenticatedmodal为true,那么我们toggle (关闭)模式,否则我们记录错误。

但是,即使我看到 Redux DevTool 执行 user/login/fulfilled 操作,并且 isAuthenticated 状态设置为 ,模式也不会关闭>true.

enter image description here

根据我的理解,当login thunk完成时,isAuthenticated应该已经设置为true,所以当我们调用时,我们已经准备好了一切.then() 方法。是不是因为我通过useSelector得到了isAutheticated状态,所以需要一些时间来更新自己?那么我们不能保证当 Promise 返回时 React Redux 已经更新了它?成功后是否有更好的方法关闭模式?

感谢您的帮助!您可以找到演示here 。 (' [email protected] ' + 任意密码 => 成功,其他组合 => 拒绝)

最佳答案

我认为 then 回调中的 Promise 的返回值确实表示登录操作成功。但这并不意味着您将得到 isAuthenticatedtrue,因为您的 handleSubmit 将会超过 isAuthenticated< 的先前值 这是false

您需要有一个自定义的 useEffect 来触发 isAuthenticated 以及您的逻辑所需的其他值。

以下更改应该可以满足您的需求:-

  const toggle = useCallback(() => {
    setHasError(false);
    setModal((modal) => !modal);
  }, []);

  useEffect(() => {
    if (isAuthenticated && modal) {
      setEmail("");
      setPassword("");
      toggle();
    }
  }, [isAuthenticated, modal, toggle]);

  const handleSubmit = (e) => {
    e.preventDefault();
    dispatch(login({ email, password }))
      .then(unwrapResult)
      .catch(() => setHasError(true));
  };

这是代码和框:-

Edit react-modal (forked) - stackoverflow

关于javascript - Redux 工具包 createAsyncThunk 问题 : state updates after async dispatch call?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67958052/

相关文章:

ruby-on-rails - Rails 3.2.9 中的“rails console”命令抛出错误

javascript - $ 不是函数。 Backbone 、jQuery 和 Browserify

javascript - Moment JS - isAfter 返回 .isAfter 不是一个函数?

javascript - 给定操作 "X",reducer "Y"返回未定义

javascript - React - 使用 reduxForm 的两个语句之间的差异

javascript - 在顶部显示 Div ..它在 Chrome 浏览器中不起作用

javascript - 下拉菜单根据选择显示不正确的图像

reactjs - 在组件/容器中组织 React 应用程序

javascript - findDOMNode 已弃用

javascript - React 无状态组件 clearTimeout 似乎不起作用