RTK Query - Dispatch action after mutation in form submission

Viewed 1004

so I am just learning RTK query and I am trying to just dispatch an action after I run a mutation hook in a form. My code looks like this:

const Login = () => {
  const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
  } = useForm();
  const [postCredentials, { isSuccess }] = useLoginMutation();
  const dispatch = useDispatch();

  const onSubmit = async (data: any) => {
    await postCredentials({
      username: data.username,
      password: data.password,
    });
    console.log('RESULT', isSuccess);

    // {
    //   isSuccess && dispatch(setUserStatus({ isLoggedIn: true }));
    // }
  };
--------------- 

When I submit the form it does post to the end point and responds successfully(network tab in Chrome dev tools). My problem is that after the await postCredentials() function the console.log(isSuccess) is false even after I know the POST is successful. If I click again then the console.log(isSuccess) is true. Any ideas what I am doing wrong? I expect the isSuccess to be true first time around so I can then dispatch a new action. TIA

1 Answers

You have a stale reference here.

See this example:

let a = 0
function MyComponent(){
  const b = a
  function increment(){
    console.log(b)
    a++
    console.log(b)
  }
  useEffect(increment)
}

foo is your component. No matter how much you change a here, b is a copy of it and will not change. If you run the function again (which is what a component rerender would do), there will be a new variable called b within the scope of that new execution - and there will also be a new function called increment within the scope of that new execution. That "new" increment" can read the "new value" of b`, but will again not get any update to that.

So: isSuccess will never change within one execution of your onSubmit method.

What you can do instead is unwrap the result:

const onSubmit = async (data: any) => {
  try {
    const result = await postCredentials({
      username: data.username,
      password: data.password,
    }).unwrap();
    console.log('RESULT', result);
    dispatch(setUserStatus({ isLoggedIn: true }));
  } catch (e) {
  }
  };

All that said, there is also another solution: don't use setUserStatus at all.

Add a listener for the api.endpoints.postCredentials.matchFulfilled case to your user status slice's extraReducers. That way whenever postCredetials executes successfully, that slice can react to it and change accordingly.

Related