DEV Community

Ayako yk
Ayako yk

Posted on • Edited on

useContext + useReducer with Sample Code

In the previous blog posts, I discussed the functionalities of useContext and useReducer. Briefly, useContext is a React Hook that enables us to access Context or data from any components within a nested tree. useReducer is a state management hook that handles multiple states depending on the passed action types.

In today's article, I will demonstrate how we can effectively maintain large-scale applications by leveraging both useContext and useReducer.

This is a simple book list app where users can add books to read. The app displays the total number of books on the list and indicates the next book to read. It's designed as a demonstration app, intentionally kept as simple as possible without including fancy functions or even CSS.

Image description

Image description

First, let's start with only two components, <Books />and <BookList />, using only the useReducer hook.

Image description

Image description

Image description

Image description

This setup works seamlessly, as demonstrated in the images. When users enter the title of a book (e.g., "book1," "book2," "book3," and "book4") and click the delete button (e.g., deleting "book1"), the app accurately reflects the updated count (3 books) and displays the first book in the list ("book2") as the next one to read.

Now, what if we want to add a book detail page nested within the <BookList /> component? We would need to pass down books={books} and dispatch={dispatch} to that component to access the data. However, prop-drilling will occur and make data management challenging.

What if we want to create a separate component for the top part, including "Books to Read," "Number of books in my list," and "Next book to read" where the "books" data is required for display?

Here's the solution: Using useContext.
Let's examine this step by step.

BookContext.js
We create BookContext using createContext.

Image description

BookProvider.jsx
In this component, we define a reducer so that we can successfully pass the action types via the Provider using value={}.
Here, initialState, reducer, and useReducer all come from the <Books />component.

Image description

App.js
To use the context, we wrap <Header /> and <Books /> with the provider we created. Now, we have access to the books and dispatch.

Image description

Header.jsx
We have a custom hook, useBookContext, to access the needed data. On this page, we only need access to book.

Image description

BookList.jsx
Here, we use useBookContext to access both book and dispatch.

Image description

Books.jsx
Now, the code is simplified and easy to read.
There's no need to pass book={book} and dispatch={dispatch} explicitly.

Image description

Image description

Image description

The action types in the reducer precisely define the actions to take, ensuring the maintenance of an immutable state. useContext makes it easy for components to access only the necessary data without the need to pass it all the way down to child components. This combination of useContext and useReducer contributes to making large-scale applications more readable, manageable, and dynamic!

Some developers choose to create separate files exclusively for a reducer, as well as for a Context and Provider. I'll delve deeper into this approach to explore its benefits further. So many areas can be enhanced, such as using capital letters for action type constants, adding more features and styles, and implementing input field validations. These aspects could become my next project as I continue to refine and expand this undertaking.

I've noticed that some developers engage in debates over "useContext + useReducer vs Redux." Now, I'm excited to learn more about Redux.

Update:
I elevated the project by incorporating TypeScript, enhancing the application's type safety and robustness.

Home
The Home page presents the user's book list, displayed at the bottom. A card at the top showcases the total number of books in the list. Additionally, a recommended book, which is the first in the list, is featured at the top. The integration of useContext and useReducer enhances state management.

Add/Edit
This section empowers users to create new books or edit existing ones. When editing, the form displays the existing data for seamless modification.

Show
In this section, users gain access to detailed information about a specific book from their list.

Edit Tags
The Edit Tags page leverages the power of react-select to simplify the selection, creation, editing, and deletion of tags. This library provides an intuitive interface for managing multiple tags associated with books.

Image description

Top comments (0)