Redux Toolkit createAsyncThunk 问题:异步调度调用后状态更新?
Redux Toolkit createAsyncThunk question: state updates after async dispatch call?
我正在学习 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
中,如果用户认证成功,我想关闭模式,如果失败,则显示错误信息。为了像正常的 promise 内容一样对待 action,我在 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
,然后如果承诺return成功加上状态isAuthenticated
和modal
为真那么我们toggle
(关闭) 模式,否则我们记录错误。
但是,即使我看到 Redux DevTool 执行了 user/login/fulfilled
操作并且 isAuthenticated
状态设置为 true
.[=55=,模态框也没有关闭]
根据我的理解,当 login
thunk 完成时,isAuthenticated
应该已经设置为 true
,所以我们在调用 .then()
方法时一切就绪.是不是因为我通过useSelector
得到了isAutheticated
状态,所以需要一些时间来更新自己?所以我们不能保证 React Redux 在 promise return 时已经更新了它?成功后有没有更好的方法关闭模态?
感谢您的帮助!您可以找到演示 here。 ('right@gmail.com' + 任意密码 => 成功,其他组合 => 拒绝)
我认为 then
回调中 Promise
的 return 值确实表示登录操作成功。但这并不意味着您将获得 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));
};
这是代码和框:-
我正在学习 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
中,如果用户认证成功,我想关闭模式,如果失败,则显示错误信息。为了像正常的 promise 内容一样对待 action,我在 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
,然后如果承诺return成功加上状态isAuthenticated
和modal
为真那么我们toggle
(关闭) 模式,否则我们记录错误。
但是,即使我看到 Redux DevTool 执行了 user/login/fulfilled
操作并且 isAuthenticated
状态设置为 true
.[=55=,模态框也没有关闭]
根据我的理解,当 login
thunk 完成时,isAuthenticated
应该已经设置为 true
,所以我们在调用 .then()
方法时一切就绪.是不是因为我通过useSelector
得到了isAutheticated
状态,所以需要一些时间来更新自己?所以我们不能保证 React Redux 在 promise return 时已经更新了它?成功后有没有更好的方法关闭模态?
感谢您的帮助!您可以找到演示 here。 ('right@gmail.com' + 任意密码 => 成功,其他组合 => 拒绝)
我认为 then
回调中 Promise
的 return 值确实表示登录操作成功。但这并不意味着您将获得 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));
};
这是代码和框:-