React Hooks. Pass value as argument to useReducer()

Viewed 3622

It is my first time using useReducer() hook and I am facing a problem where I need to pass it a value as argument.

Here is how my reducer looks like:

  const memoizedReducer = useCallback((state, action) => {
    switch (action.type) {
      case "save":
        const refreshedBookData = {
          ...state.bookData,
          ...(state.bookData.totalSaves >= 0 && {
            totalSaves: state.bookData.totalSaves + 1,
          }),
          isSaved: true,
        };
       
        // Add the new book data to a Map which I have in a Context provider
        currentUser.addBookToVisitedBooks(bookId, refreshedBookData);
        
        // Update my context provider data
        currentUser.setData((prevCurrentUserData) => {
          return {
            ...prevCurrentUserData,
            ...(prevCurrentUserData.totalSaves >= 0 && {
              totalSaves: prevCurrentUserData.totalSaves + 1,
            }),
          };
        });
        
        return refreshedBookData;

    case "unsave":
        const refreshedBookData = {
          ...state.bookData,
          ...(state.otheBookData.totalSaves >= 0 && {
            totalSaves: state.bookData.totalSaves - 1,
          }),
          isSaved: false,
        };

        // Add the new book data to a Map which I have in a Context provider
        currentUser.addBookToVisitedBooks(bookId, refreshedBookData);
      
        // Update my context provider data
        currentUser.setData((prevCurrentUserData) => {
          return {
            ...prevCurrentUserData,
            ...(prevCurrentUserData.totalSaves > 0 && {
              totalSaves: prevCurrentUserData.totalSaves - 1,
            }),
          };
        });
        
        return refreshedBookData;
      
    default:
        return state;
});


const [{ bookData }, dispatch] = useReducer(memoizedReducer, {
   bookData: params?.bookData
});

As you can see, what I am doing is:

1- If the action type is "save", increase the total saves for the book, add the new book data to a Map of "visitedBooks" which I have in a Context (ignore this part), and update my currentUser data increasing his total saves.

2- If the action type is "unsave", I do the opposite.

My problem is that I need to pass an argument "reviews" to the reducer. For example, if I have this function for fetching "extra data" from my db:

   const fetchReviews = async (bookId) => {
       // Get a list of reviews from the db
       const reviews = await db.fetchReviews(bookId);

       return reviews;
   }  

and I use it like this:

  const reviews = await fetchReviews(bookId);
  

how can I pass the reviews as argument to the reducer?

  dispatch({ type: saved ? "save" : "unsave" }); 

Thank you.

2 Answers

You already pass down an object to dispatch() and nothing stops you to add a payload along with the type:

dispatch({ 
  type: saved ? "save" : "unsave",
  payload: reviews,
});

This way you can access the reviews in your reducer (action.payload).

const reducer = (state, action) => {
  // action has `type` and `payload` properties
}

When you call the dispatch method, you're passing an object which has the type field. The format of this object is actually up to you to define. If you need to pass parameters other than type you can freely do so.

For example


const reviews = {....} ; /// reviews  
dispatch({ type: 'save', payload: reviews });

Then in your reducer you can you the payload object

// Reducer 

const reducer = (state, action) => {
    switch (action.type) {
        case 'save':
            const reviews = action.payload;
            //.....
            break;
    }
}

I suggest reading this article https://redux.js.org/basics/actions

Related