I have an asynchronous Thunk:
export const loginThunk = createAsyncThunk(
"user/login",
async ({ login, password }: { login: string; password: string }) => {
const { token } = await authService.login(login, password);
return token;
}
);
Using it in store:
extraReducers: (builder) => {
builder
.addCase(loginThunk.fulfilled, (state, action) => {
state.token = action.payload;
state.isLoading = false;
state.error = false;
})
.addCase(loginThunk.pending, (state) => {
state.isLoading = true;
state.error = false;
})
.addCase(loginThunk.rejected, (state, action) => {
state.isLoading = false;
state.error = true;
})
Target component:
const Auth = () => {
const dispatch = useAppDispatch();
const { token, error } = useAppSelector((state) => state.auth);
const [login, setLogin] = useState("");
const [password, setPassword] = useState("");
const navigate = useNavigate();
const onSubmitHandle = async (e: FormEvent) => {
e.preventDefault();
if (login !== "" && password !== "") {
await dispatch(loginThunk({ login: login, password: password }));
!error && token !== null ? navigate("/editor") : null;
}
};
return (
<div className="login">
<form className="login__form" onSubmit={onSubmitHandle}>
<h2 className="login__title">Editor</h2>
<label className="login-form__label">
Login
<input
type="text"
name="login"
onChange={(e) => setLogin(e.target.value)}
/>
</label>
<label className="login-form__label">
Пароль
<input
type="text"
name="password"
onChange={(e) => setPassword(e.target.value)}
/>
</label>
<button type="submit" className="login__button">
Enter
</button>
{error ? "Error, try do it later" : null}
</form>
</div>
);
};
After click "Enter" I get token and put it to store. In Redux-Devtools I see that token is in store, but component doesn't update. Interesting, but component updating, if I change field error, but token no.
createAsyncThunks
always resolve. If you are wanting to use the returned token
value then you need to do two things.
unwrap
the resolved result. See Handling Think Results for more details.token
value instead of referencing the stale closure over the selected token
value from the outer scope.Example:
const onSubmitHandle = async (e: FormEvent) => {
e.preventDefault();
if (login !== "" && password !== "") {
try {
const token = await dispatch(
loginThunk({ login, password })
).unwrap(); // <-- unwrap Thunk result
// If we get this far then no error yet
if (token !== null) {
navigate("/editor");
}
} catch(error) {
// catch/handle any thrown errors or rejected Promises
}
}
};