How to add global state to a small react app

The context api provided by React is enough and powerful than adding the whole react-redux library. I have a dynamic page that is served by Nextjs. I want a contact form in multiple styles, which means I cannot make the form a component. There are multiple templates in this page that is loaded according to the data from firebase. The contact form takes in the username and an email address and save it to the database.

1. Create a file context.js

import React, { Component } from "react";

const UserContext = React.createContext({});
export const UserConsumer = UserContext.Consumer;
export default UserContext;

export class UserProvider extends Component {
 state = {
   name: "",
   email: ""
 };
 
 render() {
   return (
     <UserContext.Provider
       value={{
         state: this.state
       }}
     >
       {this.props.children}
     </UserContext.Provider>
   );
 }
}

We need a provider for storing the data. The UserProvider can be used to store the value in a state and pass this to the component that is wrapped with this provider. We are also exporting UserContext to consume this value anywhere in the child component of the provider.

2. Consuming the value in functional component

import React, { useContext } from "react";
import "./template1.scss";
import UserContext from "../context/context";

const Template1 = ({ user }) => {
  const context = useContext(UserContext);
  const { name, email} = context.state;

    return <div>{name}</div>
}

React provides a hook useContext to access value from the provider. This hook takes in the context as the argument and returns the access to the value passed to the provider. So here we accessed the email and name from the state key in the context.

3. Update value of context by passing functions

...// add this method to context.js
updateValue = v => {
    if (v.email) {
      this.setState({
        ...v,
        error: "",
        emailValid: !!isValidEmail(v.email)
      });
    } else {
      this.setState({
        ...v,
        error: ""
      });
    }
  };
...
... // attach the function to the provider value
 <UserContext.Provider
        value={{
          state: this.state,
          updateValue: this.updateValue,
        }}
      >
        {this.props.children}
      </UserContext.Provider>
    );
...
Adding method to UserProvider class

The above code adds a method to the UserProvider class so that, when it is triggered it can update the state of the provider.

Now we will access the method in the context of the component

...
const handleEmailChange = e => {
    context.updateValue({ email: e.target.value });
  };
const handleNameChange = e => {
    context.updateValue({ name: e.target.value });
  };
...
calling the function in the component

The onChange event of input triggers the function in this case. The state will be updated by the provider component and the page updates with new value.

The context api helps a lot in the case of prop drilling.

Hope this helped you in someway.