【发布时间】:2021-08-29 15:21:13
【问题描述】:
我现在正在学习 Redux Thunk。我尝试使用Redux Toolkit中的createAsyncThunk来处理用户登录,但遇到了一些问题。我在这里创建了一个demo('right@gmail.com' + 任何密码 => 成功,其他组合 => 拒绝)。
我创建了一个模式供用户使用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文件中,当点击登录按钮时,它会启动表单提交功能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 中,如果用户身份验证成功,我想关闭模式,如果失败,则显示错误消息。为了将操作视为正常的承诺内容,我在 Redux Toolkits (here) 中找到了这个:
createAsyncThunk 生成的 thunk 将始终返回一个已解决的 Promise,其中包含已完成的操作对象或被拒绝的操作对象,视情况而定。
调用逻辑可能希望将这些操作视为原始承诺内容。 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返回成功加上状态isAuthenticated和modal为真,那么我们toggle(关闭)模式,否则我们记录错误。
但是,即使我看到 Redux DevTool 执行 user/login/fulfilled 操作,模态也不会关闭,并且 isAuthenticated 状态设置为 true。
在我的理解中,login thunk 完成时,isAuthenticated 应该已经设置为 true,所以当我们调用 .then() 方法时,我们已经准备好了一切。是不是因为我通过useSelector得到了isAutheticated状态,所以需要一些时间来更新自己?所以我们不能保证当 Promise 返回时 React Redux 已经更新了?成功后有没有更好的方法来关闭模态框?
感谢您的帮助!你可以找到演示here。 ('right@gmail.com' + 任何密码 => 成功,其他组合 => 拒绝)
【问题讨论】:
标签: javascript reactjs redux react-redux redux-toolkit