React Context API & useReducer: State Management Guide

Avinash Vagh - Jul 16 '22 - - Dev Community

The Context API provides a clean and efficient way to share state within a React component tree. It addresses the issues of prop drilling, which can be messy and frustrating when passing props down to components.

Using the Context API, you can pass props to any child component of a parent, allowing state sharing without having to pass props at each level.

Provider and Consumer

The Context API has two main components:

  1. Provider
  2. Consumer

The Provider is a React component that wraps other components, while the Consumer consumes the data or state passed through the Provider.

It's important to note that the Context API is preferred for passing global data. If that's the case, it's likely a good choice.

Implementing a Provider

import React, { createContext } from 'react';

export const AuthContext = createContext()

function AuthContextProvider(){
    const [isAuth, setIsAuth] = React.useState(false)
    return (
        <AuthContext.Provider value={setIsAuth, isAuth}>
            {this.props.children}
        </AuthContext>
    )
}

export default AuthContextProvider

Enter fullscreen mode Exit fullscreen mode

Using a Consumer in a Child Component

import React from 'react'
import { AuthContext } from "../pathToFile"

function LoginForm (){
    const {isAuth, setIsAuth} = React.useContext( AuthContext )
    return(
            <div>
                {isAuth ? "LOGGED IN" : "LOGGED OUT"}
            </div>
        )
}

Enter fullscreen mode Exit fullscreen mode

React Composition vs Inheritance Explained

React Composition vs Inheritance is a concept that is widely used in React applications. It's important to understand the difference between the two in order to build efficient and scalable applications.

Using Children Props in React Components:

Some components in React applications may not know their children ahead of time. For example, components like Sidebar or Dialog represent generic "boxes." In such cases, we can use a prop called children to pass children elements directly into their output. Here is an example of how to use the children prop in a Form component:

import React from 'react';
import styles from './Form.module.css'

function Form(props){
    const { children,onSubmit } = props;
    return (
        <form onSubmit={onSubmit} className={styles.myForm}>
            {children}
        </form>
    )
}

export default Form;

Enter fullscreen mode Exit fullscreen mode

In the above code, the Form component accepts a children prop and renders it directly into its output. This allows the parent component to pass in any number of children elements.

Passing Components as Props in React Applications:

Sometimes, you may need multiple "holes" in a component. In such cases, you can come up with your own convention instead of using children. For example, you can pass components as props. Here is an example of how to pass components as props in a Menu component:

import React from "react";
import styles from "./child.module.css";

const Menu = props => {
  console.log("hello");
  return (
    <div className={styles.cont}>
      <div>{props.left}</div>
      <div>{props.right}</div>
    </div>
  );
};

const Title = ({ label }) => <div>{label}</div>;

const Children2 = props => (
  <div>
    <Menu left={<Title label="LEFT" />} right={<Title label="RIGHT" />} />
  </div>
);

// OR

const Children2 = props => (
  <div>
    <Menu left={"LEFT"} right={"RIGHT"} />
  </div>
);

export default Children2;

Enter fullscreen mode Exit fullscreen mode

In the above code, the Menu component accepts two components, left and right, as props. These components are then rendered directly into the output of the Menu component.

useReducer Hook in React - An Alternative to useState

What is useReducer in React?

useReducer is a built-in React Hook that is an alternative to useState. It accepts a reducer function of type (state, action) => newState and an initial state, and returns the current state and a dispatch function.

Benefits of Using useReducer over useState

When you have complex state logic that involves multiple sub-values or when the next state depends on the previous one, useReducer is usually preferable to useState.

Using useReducer also allows you to optimize the performance of components that trigger deep updates because you can pass dispatch down instead of callbacks.

The useReducer Hook accepts two arguments: a reducer function and an initial state. It returns an array of two values that can be destructured to the current value of the state and a dispatch function.

The reducer is a function that accepts the state and an action, and based on these arguments, it determines how the value of the state will change. The dispatch function is how we pass an action to the reducer function. It dispatches the action to be used to update the state.

To illustrate how useReducer works, let's take the example of a counter:

const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

There are two ways to initialize the useReducer state. You can pass the initial state as a second argument, as shown in the example above. Alternatively, you can define an initial state within the reducer function.

Codesandbox Example

Context API & useReducer Codesandbox Example

That's it for this comprehensive guide on React Context API and the useReducer Hook. Stay tuned for more articles, don't forget to follow me on Twitter and connect with me on LinkedIn for updates. Also, check out my Medium Blog for more content.

Stay fit, keep coding, explore, and enjoy what you do.

. . . . . . . . . . . . . . . . . . . . . . .