'Passing arguments to actions in Redux

I am using the redux toolkit, (the new update of redux in case you're still using the deprecated older version) with React and I am using the createAsyncThunk method (or middleware if you prefer) to perform an API call to my backend API.

Here, I can do two things, either run the async call inside the component and check whether the API call succeeds or fails, and render something based on that, or I can perform the Async API call inside the action creator itself (inside the createSlice in case you're using the Redux toolkit).

Personally, I believe that the second approach is more abstract and cleaner for the components, but the main problem is that I can't handle the errors there. In other words, take this example, I wanted to getAllPosts, I can simply dispatch an action using dispatch(getAllPosts()) within the component, and let the Async logic and error handling be inside the action creator getAllPosts. But in case of a failed Async call, I can't return an error to the component to render a red message saying "there was an error while fetching the posts".

I thought I could pass a callback function as an argument to the getAllPosts action creator, and make this callback function a callback that only runs in case of a failure. ex:

dispatch(getAllPosts(payloadObj, ()=> { /* do something here in case of an error* / } ))

The questions are:

  • What do you think about my solution? Is it the best or is there a standardized way of doing this?
  • How do I pass the callback function argument I described to the getAllPosts method? Can I simply add a second argument to the getAllPosts method? Or is that not possible in redux-toolkit? Do I have to pass my callback function as the first argument? But having it the first argument will make redux-toolkit wrap it inside a payload property because it's assumed that what I am passing is a new state.


Solution 1:[1]

The correct answer here is to follow the pattern shown in Redux Essentials Part 5: Async Logic - Checking Thunk Results in Components.

If the thunk function returns a promise, that will be returned from dispatch(thatAsyncThunk()).

RTK's createAsyncThunk in particular will end up returning a promise with a special .unwrap() method that either returns the result if successful, or throws an error if it failed.

So, the right technique in a component is:

const fetchPokemonByName = createAsyncThunk(
  'fetchPokemonByName',
  async (name) => {
    const res = await imaginaryPokemonApi.getByName(name);
    return res.data;
  }
)

// later, in a component
function SomeComponent() {
  const dispatch = useDispatch();

  const handleClick = async () => {
    try {
      const pokemon = await dispatch(fetchPokemonByName("pikachu")).unwrap();
      console.log("Entry: ", pokemon);
    } catch (err) {
      console.error("Failed to fetch pokemon: ", err);
    }
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 markerikson