Search code examples
reactjsreact-reduxredux-thunkredux-toolkit

Redux Toolkit: createAsyncThunk - rejectWithValue - TypeError: Cannot destructure property 'rejectWithValue' of '_ref2' as it is undefined."


I've been trying to make auth refresh token calls using Redux toolkit but after installing all fixes, it still is now able to read error message.

Setting up axios instance:

export const axiosInstance = axios.create({
  baseURL: REACT_APP_API_URL,
});

Making API call:

export const refreshAccessAndRefreshTokens = async () => {
  const response = await axiosInstance({
    method: 'post',
    url: '/refresh-tokens',
    withCredentials: true,
  });
  return response;
};

Thunk function:

// GET ACCESS TOKEN USING REFRESH TOKEN
export const refreshTokens = createAsyncThunk(
  'auth/refreshTokens',
  async ({ rejectWithValue }) => {
    try {
      const response = await refreshAccessAndRefreshTokens();
      return response.data;
    } catch (error) {
      console.log('error', error);
      console.log('data', error.response.data);
      console.log('message', error.response.data.message);
      return rejectWithValue(error.response.data.message);
    }
  }
);

Extra reducers in auth slice:

extraReducers: (builder) => {
    builder
      .addCase(refreshTokens.pending, (state) => {
        state.loading = true;
      })
      .addCase(refreshTokens.fulfilled, (state, action) => {
        state.loading = false;
        state.isAuthenticated = true;
        state.user = action.payload.user;
        state.roles = action.payload.roles;
      })
      .addCase(refreshTokens.rejected, (state, action) => {
        state.loading = false;
        state.success = false;
        state.message = action.payload;
        state.isAuthenticated = false;
        state.user = null;
        state.roles = [];
      })
  },

I'm able to see the errors in browser console, but rejectWithMessage is not working:

Console output:

console output

Redux output:

redux output

Refresh Tokens is being called on login page through useEffect to redirect the user to where he came from in case he is already logged in.

useEffect(() => {
    dispatch(refreshTokens());
    dispatch(reset());
  }, [dispatch]);

  useEffect(() => {
    if (isAuthenticated) {
      if (roles.find((role) => role === process.env.REACT_APP_ROLE)) {
        navigate(from, { replace: true });
      } else {
        dispatch(
          errorFn({
            success: false,
            message: 'You are not authorized to access this page!',
          })
        );
      }
    }
  }, [dispatch, from, isAuthenticated, navigate, roles]);

Solution

  • The first argument that is passed to the callback function you give to createAsyncThunk is the argument that you pass when you call the action. take a look here for more information. The second argument is the thunkAPI which contains the rejectWithValue. Try putting a dummy parameter as the first parameter to the callback like this -

    // GET ACCESS TOKEN USING REFRESH TOKEN
    export const refreshTokens = createAsyncThunk(
      'auth/refreshTokens',
      async (_, { rejectWithValue }) => {
        try {
          const response = await refreshAccessAndRefreshTokens();
          return response.data;
        } catch (error) {
          console.log('error', error);
          console.log('data', error.response.data);
          console.log('message', error.response.data.message);
          return rejectWithValue(error.response.data.message);
        }
      }
    );