DEV Community

notdennis
notdennis

Posted on

Understanding React Context API and UseReducer Hooks for beginner

Article Objective

By the end of this article, the reader will have a clear grasp of the concept of Context API and the useReducer hook. They will also be able to apply these skills to various React projects. This article is targeted towards beginners.

What is Context API?

React Context API was officially introduced in React v16.3 to address the problem of "props drilling" in React. This API offers a solution for passing data through the component tree without the need to manually pass props down at every level. React Context API was influenced by popular state management libraries such as Redux.

Let’s Explore How We Would Use React Context API

To establish a context in React, we utilize the "createContext" keyword. This approach grants us access to a provider and consumer component, which can prove to be quite useful.

import React,{createContext} from 'react';

const newContext = createContext({color: 'blue'})

const { Provider, Consumer } = newContext;
Enter fullscreen mode Exit fullscreen mode

The provider component is a useful tool that enables all child components, regardless of their nesting level, to access the state. This is achieved by wrapping the index file or root component. However, it is important to note that a value prop must be passed in order to provide the current data or state. This ensures that the component is able to function properly and deliver the necessary information. Overall, the provider component is an essential element in the development of robust and effective applications.

<Provider value={color: 'blue'}>
  {children}
</Provider>

Enter fullscreen mode Exit fullscreen mode

UseContext Hook

The useContext hooks are a useful tool for effectively utilizing the createContext API. This API returns a context object, which can then be passed into the useContext hook to access the current context value for that specific context. By doing so, developers can more easily manage and manipulate the data within that context, ultimately improving the overall functionality and efficiency of their code.

import React,{createContext} from 'react';

const newContext = createContext(color: 'blue')

function Index() {
  return (
    <newContext.Provider value={color: 'blue'}>
      <App />
    </newContext.Provider>
  );
}

function App(props) {
  return (
    <div>
      <ShowColor />
    </div>
  );
}

function ShowColor() {
  const color = useContext(newContext) 
  return (
   <h1>{color} </h1>
  )
}
Enter fullscreen mode Exit fullscreen mode

The provided code snippet comprises three crucial components that work in harmony to ensure seamless functionality. The first component is the Index, which serves as the root and has other subordinate components as its children. In this context, we utilize the provider to facilitate the provision of data and state for the entire application. Moving on, the App component wraps the ShowColor component, which is where we employ the useContext hook to efficiently consume the data. This methodology ensures that all the components work together, providing a smooth and coherent user experience.

useReducer Hook

The useReducer hook is a highly useful state management tool that works in a manner similar to Redux. Its primary purpose is to manage the state of our app, much like the useState or class component state. However, what sets useReducer apart is its ability to handle complex state logic, making it an ideal choice for global state management with the help of the context API. This powerful hook is modeled after the widely popular third-party state management library, Redux, which aids in managing app state and eliminating prop drilling. With useReducer, developers can manage complex state with ease, making it a crucial tool for any modern app development project.

In order to effectively utilize the useReducer hook in React, it is necessary to have three key components: the Action, Reducer, and State. The reducer function is the central component of this process, as it takes in props as input and returns the current state, paired with a method. Essentially, it is responsible for defining the behavior of the actions that are taken within the application. When the reducer function receives the current state, it performs the requested action and subsequently returns a new state.

On the other hand, the Action component is an object that is responsible for sending data to the state. Typically, this component consists of two distinct properties: the type property, which describes the action that is being performed, and the payload property, which contains the information that needs to be modified in the app state.

Finally, the State component serves as the single source of truth for our application. It maintains a record of the current snapshot of the application's state at any given point in time. As an example, consider the implementation of a counter application that utilizes useReducer. Overall, understanding the role of each of these components is critical to effectively utilizing useReducer within a React application.

Here is a simple code snippet on how to make use of UseReducer and Context Api effectively

import React, { createContext, useContext, useReducer } from 'react';

// Create a new context
const ListContext = createContext();

// Reducer function
const listReducer = (state, action) => {
  switch (action.type) {
    case 'ADD_ITEM':
      return [...state, action.payload];
    case 'REMOVE_ITEM':
      return state.filter(item => item !== action.payload);
    default:
      return state;
  }
};

// Custom hook to access the context
export const useListContext = () => {
  return useContext(ListContext);
};

// Context Provider component
export const ListProvider = ({ children }) => {
  const [list, dispatch] = useReducer(listReducer, []);

  return (
    <ListContext.Provider value={{ list, dispatch }}>
      {children}
    </ListContext.Provider>
  );
};

Enter fullscreen mode Exit fullscreen mode

Use the context in your main App.js component:

import React from 'react';
import { ListProvider } from './ListContext';
import ItemList from './ItemList';

function App() {
  return (
    <ListProvider>
      <div className="App">
        <h1>Item List</h1>
        <ItemList />
      </div>
    </ListProvider>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Create another component ItemList.js to display and interact with the list:

import React from 'react';
import { useListContext } from './ListContext';

const ItemList = () => {
  const { list, dispatch } = useListContext();

  const addItem = () => {
    dispatch({ type: 'ADD_ITEM', payload: `Item ${list.length + 1}` });
  };

  const removeItem = item => {
    dispatch({ type: 'REMOVE_ITEM', payload: item });
  };

  return (
    <div>
      <button onClick={addItem}>Add Item</button>
      <ul>
        {list.map(item => (
          <li key={item}>
            {item}
            <button onClick={() => removeItem(item)}>Remove</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default ItemList;

Enter fullscreen mode Exit fullscreen mode

In this example, we create a context named ListContext which includes a reducer to manage the list state. We define a custom hook useListContext to easily access the context values within components. The ListProvider component wraps the application, and the ItemList component uses the context to display and interact with the list.

Remember that this is a basic example of how the Context API can be used to manage the state in a React application. In more complex scenarios, you might want to consider using Redux or other state management libraries for better scalability and advanced features.

Top comments (0)