我现在正在学习 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
函数将处理异步调用以获取数据,因为我使用了 createAsyncThunk
。 createAsyncThunk
将创建三个操作:pending
、fulfilled
和 rejected
。我在 userSlice
的 extraReducers
中相应地定义了操作。
// 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返回成功并且状态isAuthenticated
和modal
为true,那么我们toggle
(关闭)模式,否则我们记录错误。
但是,即使我看到 Redux DevTool 执行 user/login/fulfilled
操作,并且 isAuthenticated
状态设置为 ,模式也不会关闭>true
.
根据我的理解,当login
thunk完成时,isAuthenticated
应该已经设置为true
,所以当我们调用时,我们已经准备好了一切.then()
方法。是不是因为我通过useSelector得到了isAutheticated状态,所以需要一些时间来更新自己?那么我们不能保证当 Promise 返回时 React Redux 已经更新了它?成功后是否有更好的方法关闭模式?
感谢您的帮助!您可以找到演示here 。 (' [email protected] ' + 任意密码 => 成功,其他组合 => 拒绝)
最佳答案
我认为 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));
};
这是代码和框:-
关于javascript - Redux 工具包 createAsyncThunk 问题 : state updates after async dispatch call?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67958052/