Redux工具包创建AsyncThunk问题:异步调度调用后的状态更新?

4xy9mtcn  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(176)

我现在正在学习Redux Thunk。我尝试使用Redux Toolkit中的createAsyncThunk来处理用户登录,但遇到了一些问题。我在这里创建了一个demo(“right@gmail.com”+ whatever password =〉success,other combination =〉reject)。
我创建了一个模态用户输入他们的电子邮件和密码使用reactstrap。点击Login按钮,然后你会看到的形式。
下面是我的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文件中,当单击Login按钮时,将启动表单提交函数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中,如果用户身份验证成功,我希望关闭模态,如果失败,则显示错误消息。为了将此操作视为正常的承诺内容,我在Redux Toolkits(here)中找到了以下内容:
由createAsyncThunk生成的thunk将始终返回一个已解析的承诺,其中包含已实现的操作对象或已拒绝的操作对象(根据需要)。
调用逻辑可能希望将这些操作视为原始承诺内容。Redux Toolkit导出一个unwrapResult函数,该函数可用于提取已实现操作的有效负载,或抛出错误,或从被拒绝的操作中抛出由rejectWithValue创建的有效负载(如果可用)。
所以我把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为真,则我们使用toggle(关闭)模态,否则我们记录错误。
但是,即使我看到Redux DevTool执行了user/login/fulfilled操作,并且isAuthenticated状态设置为true,模态也不会关闭。

在我的理解中,当login thunk完成时,isAuthenticated应该已经被设置为true,所以当我们调用.then()方法时,一切都已经准备好了。所以它需要一些时间来更新自己?2所以我们不能保证React Redux在promise返回时已经更新了它?3有没有更好的方法在成功时关闭模态?
感谢您的帮助!您可以找到演示here.('right@gmail.com' +无论密码=〉成功,其他组合=〉拒绝)

bq3bfh9z

bq3bfh9z1#

我认为then回调函数中Promise的返回值表示登录操作成功,但这并不意味着isAuthenticated将作为true,因为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));
  };

下面是代码和框:-

相关问题