Understanding useContext in React

Understanding useContext in React

useContext

In React, context is more like a global variable that can be used across all components in an application. An example of when to use the context hook is to set the preferred theme or to store the currently signed-in user.

You should use the context hook only when you need some data to be accessible by many components.

working with useContext

To understand useContext better we'll be creating a context that stores a user's details and we'll be showing some things to the user if their details are stored in the context.

First things

You should have a react app created already and install react-router-dom from npm (just for this example, you don't need react-router-dom for useContext). Now create a file in your source folder and name it userDetails.jsx this is the file that will be creating the context. Then do this.

import { useState, createContext, useMemo } from 'react';

const UserContext = createContext(); 

const UserProvider = (props) => {
    const [username, setUsername] = useState('');
// the state that we'll be storing the username into

/* because we will be providing an object to the provider, it is better to put the value inside a useMemo so that the component will only re-render when there's a change in the value. */

const value = useMemo(
   () => ({username, setUsername}),[username])


    return (
        <UserContext.Provider
            value={value}
        >
            {props.children}
        </UserContext.Provider>
    );
}
export { UserContext, UserProvider };

In the code above, we just created a context called UserContext using react's createContext(), create context will tell react that we want to create a global variable. Then we created a component that contains the state we want to access globally. You'll notice that we're using a provider from the UserContext. UserContext.Provider The provider is a method from useContext that we can warp all the other components in like we're about to do in our App component.

You will also notice that we used the useMemo hook to store the values in the provider, this is to prevent the app from re-rendering when there's no update in the value. (if you aren't familiar with the useMemo hook, don't sweat it because we'll be looking at useMemo in the next section). Erik Westra talked more about that in this post.

In the App.jsx file import the UserProvider that was exported.

import { BrowserRouter, Switch, Route } from "react-router-dom";
import { UserProvider } from './userDetails';

const App = () =>  {
  return (
  <UserProvider>
      <BrowserRouter>
        <Switch>
          <Route path="/" exact component={SetUserDetails} />
          <Route
             path="/user"
             exact
             component={FetchUserDetails} />
        </Switch>
      </BrowserRouter>
    </UserProvider>
 )
}

export default App;

In the code above we're wrapping the provider into our other components. Let's create the components in the Route and use the context inside them.

Create a file and name it SetUserDetails.jsx and paste this in the file

import React, { useState, useContext } from "react";
import { useHistory } from "react-router-dom";
import { UserContext } from "./userDetails";

const SetUserDetails = () => {
  const [name, setName] = useState("");
  const history = useHistory();

  const { setUsername } = useContext(UserContext);
  const handleSetName = () => {
    setUsername(name);
    history.push("/user");
  };
  return (
    <>
      <input 
          value={name} 
          onChange={(e) => setName(e.target.value)} />
      <button onClick={handleSetName}>Set Name </button>
    </>
  );
};

export default SetUserDetails;

In the code above we created a component that accepts a username and stores it into our context. You'll notice the use of the useContext hook. We're using the hook to get the context we created earlier, in this case, we're getting setUsername. Once the user clicks on the button it will assign the name in this local state to the context.

Next, let's get the context. Create a file and name it FetchUserDetails.jsx (this is the other file in the route)

Then paste this into the file.

import React, { useContext } from "react";
import { UserContext } from "./userDetails";

const FetchUserDetails = () => {
  const { username } = useContext(UserContext);

  return <>{username ? `Hello ${username}` : `Hello User`}</>;
};

export default FetchUserDetails;

Here, we're getting the username state and checking for a value in the state. if it is empty we'll display 'Hello User', and if not we'll display the username.

Try running the code and testing it.

%[INVALID_URL]

You'll notice that the username is available in the other component. Thanks to useContext hook.

Now, try creating a context on your own and also try persisting the context.

Conclusion

This is just a basic usage for useContext there's more you can do with context, like saving a user's preferred theme or some other preferences and persisting it in your local storage.

Thank you for reading. In my next post, I'd be looking at the useMemo hook. If you enjoyed this post please like and share. If you have questions please feel free to drop them in the comments section. Keep coding and doing amazing things.