Search code examples
reactjsreduxredux-thunkredux-toolkit

How to get result from createAsyncThunk in React component Redux Toolkit


I was migrating from Apollo client to Redux toolkit and I am confusing how to use the result(success or error) of API call with createAsyncThunk and call history.push('/') and setSubmitting(false) in my React component.

Example how I did with Formik and Apollo Client:

      onSubmit={async (values, { setSubmitting }) => {
    signInMutation({
      variables: {
        email: values.email,
        password: values.password,
      },
    }).then(
      (response) => {
        if (response.data.signIn.accessToken) {
          localStorage.setItem(
            AUTH_TOKEN,
            response.data.signIn.accessToken,
          );
          if (response.data.signIn.User.isNew) {
            history.push('/welcome-page');
          } else {
            history.push('/');
          }
          setSubmitting(false);
        }
      },
      (err) => {
        console.log(`error signin ${err}`);
        enqueueSnackbar(err.message, {
          variant: 'error',
        });
        setSubmitting(false);
      },
    );

Solution

  • When you call createAsyncThunk, it will return an Action Creator which redux-thunk can use.

    You should use the function like this:

    const actionCreator = createAsyncThunk('prefix', async function echo(text) {
      return text;
    });
    
    // app.js
    import { unwrapResult } from '@reduxjs/toolkit';
    
    function App() {
      const dispatch = useDispatch();
    
      return (
        <button
          onClick={() => {
            dispatch(actionCreator('233'))
              .then(unwrapResult)
              .then((result) => {
                console.log(result); // => 233
              })
              .catch((error) => {
                console.error(error); // if there is an error
              });
          }}
        >
          Echo
        </button>
      );
    }
    
    

    This is what unwrapResult does:

    // @reduxjs/toolkit
    export function unwrapResult<R extends ActionTypesWithOptionalErrorAction>(
      returned: R
    ): PayloadForActionTypesExcludingErrorActions<R> {
      if ('error' in returned) {
        throw returned.error
      }
      return (returned as any).payload
    }
    

    To handle errors, there are two ways. The first is to throw them directly, and the second is to return rejectWithValue.

    async function echo(text, { rejectWithValue }) {
      if (Math.random() < 0.5) {
        // throw new Error('error msg');
        // return rejectWithValue('error value');
      }
      return text;
    }
    
    dispatch(actionCreator('233'))
      .then(unwrapResult)
      .then((result) => {
        console.log(result); // => 233
      })
      .catch((error) => {
        // by throw new Error('error msg');
        console.log(error.message); // => error msg
        // by return rejectWithValue('error value')
        console.log(error); // => error value
      });