你怎样在使用redux-toolkit和createAsyncThunk()完成后进行导航?

huangapple go评论56阅读模式
英文:

How do you navigate once your action has completed with redux-toolkit and createAsyncThunk()?

问题

已定义的操作 signInUser

export const signInUser = createAsyncThunk(
  "auth/loginUser",
  async (user, thunkAPI) => {
    const { username, password } = user;
    try {
      const res = await axios.post("/api/auth/login", { username, password });
      thunkAPI.dispatch(loginUser(res.data));
    } catch (err) {
      console.log(err.message);
      thunkAPI.dispatch(setErrors(err.response.data));
    }
  }
);

在表单提交时,handleSubmit() 调度 signInUser() 操作。

组件:

const Login = () => {
  const dispatch = useDispatch();
  const navigate = useNavigate();

  const handleSubmit = async (e) => {
    e.preventDefault();
    const { username, password } = formData;
    try {
      await dispatch(signInUser({ username, password }));
      // 如果 signInUser() 失败,不希望运行以下代码
      navigate("/posts");
    } catch (err) {
      console.log(err.message);
      // 如果失败,需要运行此 catch 块
    }
  };

根据我所知,无法在 signInUser() 操作内导航。因此,我尝试在 Login 组件的 handleSubmit() 中进行导航。但如果 signInUser() 操作引发了 catch(由于登录失败),则我不希望在 handleSubmit() 中执行 navigate("/posts")。我认为我需要在 handleSubmit() 中触发 catch 块,而不执行 navigate("/posts"),或以其他方式处理它。

英文:

Defined action signInUser:

export const signInUser = createAsyncThunk(
  "auth/loginUser",
  async (user, thunkAPI) => {
    const { username, password } = user;
    try {
      const res = await axios.post("/api/auth/login", { username, password });
      thunkAPI.dispatch(loginUser(res.data));
    } catch (err) {
      console.log(err.message);
      thunkAPI.dispatch(setErrors(err.response.data));
    }
  }
);

On form submission, handleSubmit() dispatches signInUser() action.

Component:

const Login = () => {
  const dispatch = useDispatch();
  const navigate = useNavigate();

  const handleSubmit = async (e) => {
    e.preventDefault();
    const { username, password } = formData;
    try {
      await dispatch(signInUser({ username, password }));
      // DON'T WANT BELOW CODE TO RUN IF signInUser() FAILS (BUT IT DOES)
      navigate("/posts");
    } catch (err) {
      console.log(err.message);
      // NEED THIS CATCH TO RUN IF IT FAILS
    }
  };

Navigation is not possible inside of the signInUser() action - as far as I know.

So I'm trying to navigate from within the handleSubmit() of the Login component. But if the signInUser() action trips its catch (from a failed login) then I don't want to navigate("/posts") in the handleSubmit(). I think I need it to trip to the catch in the handleSubmit() and not execute navigate("/posts").

Or handle it some other way?

答案1

得分: 2

createAsyncThunk Thunks always return a resolved Promise with either the fulfilled or rejected action object inside. See the Handling Thunk Results for the full details, but the basic gist is that the returned thunks have an unwrap property that extracts the fulfilled payload or throw the error object or payload if returned by rejectWithValue. See Unwrapping Result Actions.

Unwrap the returned Promise.

const handleSubmit = async (e) => {
  e.preventDefault();
  const { username, password } = formData;
  try {
    await dispatch(signInUser({ username, password })).unwrap(); // <-- unwrap Promise
    navigate("/posts");
  } catch (err) {
    console.log(err);
  }
};

If the UI needs either the value or error from the Thunk then these should also be returned.

export const signInUser = createAsyncThunk(
  "auth/loginUser",
  async (user, thunkAPI) => {
    const { username, password } = user;
    try {
      const { data } = await axios.post("/api/auth/login", { username, password });
      thunkAPI.dispatch(loginUser(data));
      return data; // <-- return POST response data
    } catch (err) {
      thunkAPI.dispatch(setErrors(err.response.data));
      return thunkAPI.rejectWithValue(err.response.data); // <-- return error payload
    }
  }
);
英文:

createAsyncThunk Thunks always return a resolved Promise with either the fulfilled or rejected action object inside. See the Handling Thunk Results for the full details, but the basic gist is that the returned thunks have an unwrap property that extracts the fulfilled payload or throw the error object or payload if returned by rejectWithValue. See Unwrapping Result Actions.

Unwrap the returned Promise.

const handleSubmit = async (e) => {
  e.preventDefault();
  const { username, password } = formData;
  try {
    await dispatch(signInUser({ username, password })).unwrap(); // <-- unwrap Promise
    navigate("/posts");
  } catch (err) {
    console.log(err);
  }
};

If the UI needs either the value or error from the Thunk then these should also be returned.

export const signInUser = createAsyncThunk(
  "auth/loginUser",
  async (user, thunkAPI) => {
    const { username, password } = user;
    try {
      const { data } = await axios.post("/api/auth/login", { username, password });
      thunkAPI.dispatch(loginUser(data));
      return data; // <-- return POST response data
    } catch (err) {
      thunkAPI.dispatch(setErrors(err.response.data));
      return thunkAPI.rejectWithValue(err.response.data); // <-- return error payload
    }
  }
);

huangapple
  • 本文由 发表于 2023年3月31日 03:32:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/75892280.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定