DEV Community

Cover image for React: Using Hooks with Global State
Ryan Moragas
Ryan Moragas

Posted on

React: Using Hooks with Global State

Passing down state in React can start to get kind of tedious. The larger the application gets, the more you'll find yourself passing down props to children components. In larger apps you may find that the components you're using to pass props down aren't even using those props at all, but need to pass them in order for children components to use the state. If you're building an app in React Native and using the React Navigator you will definitely learn how confusing it can be managing global state, especially in an app with many moving parts. In the article I'll cover how to use the useContext hook in react to give your application global state, without having to pass props down to every connecting child.

If you're new to using hooks, I would recommend reading my first article on them. It covers the useState hook, which is how I'll be manipulating the state from our global context. I know this may not be the ideal way to manage large complex global state, but it's the way that I managed to figure out how to make it work in my most recent React Native application.

Setting up useContext

The first thing that needs to be done in order to use React's useContext hook is to import it like any other hook. When using useContext it is good practice to initialize your global state in a separate file from the rest of your components. For the sake of this article we will be managing a small object that we will use for our global state, and this state will hold some user information that we want to be shared throughout or app. In a new file we will start by initialing this object.

import { createContext } from 'react';

export const UserContext = createContext({});
Enter fullscreen mode Exit fullscreen mode

Above we are importing the hook, and then making a UserContext variable that we will be manipulating. The value in the parenthesis will be the default value of this state. For now it's empty, but we will fill in the key value pairs in this object later. Now that we have initialized our global state we can pull it into our app. Since we want our entire app to be able to access this state, we will bring this state into our main app component.

import React, { useState } from 'react';
import DrawerNavigator from './navigation/DrawerNavigator';
import { UserContext } from './context/UserContext';
Enter fullscreen mode Exit fullscreen mode

This will be a react native app to further justify this example. When using react-navigator, it acts as a switch statement for what components you will display, and when. The complicated thing about using react navigation is that it makes it super difficult to pass props down to all of the children components from the components above. Above we imported the useState hook, our drawer navigator to switch between views, and the userContext value that we made above. We're all set to pass this down to the rest of our application.

export default function App () {
  const [userInfo, setUserInfo] = useState({});

  return (
    <View>
      <UserContext.Provider value={[userInfo, setUserInfo]}>
        <DrawerNavigator />
      </UserContext.Provider>
    </View>
  )
}
Enter fullscreen mode Exit fullscreen mode

Above we are initializing a new variable using the useState hook. We are calling our state userInfo, and we will be using the function setUserInfo to manipulate this state. This function's actions can be decided at call time to do exactly what we want. In our app the only thing we are rendering is our DrawerNavigator, which holds all children components. In order to use our UserContext state, we need to wrap our DrawerNavigator in the appropriate UserContext.Provider tags. We then pass the value that we want to send as this global state, and here we are also sending it with the function that we declared in our useState hook. When we wrap a component in useContext provider tags it effectively gives all children of that component access to our global state. No more passing props through any unnecessary components, you simply export the value to any child component that has to read or change these values.

import React, { useContext } from 'react';
import { UserContext } from '../context/UserContext';
Enter fullscreen mode Exit fullscreen mode

In any child component that needs to access this global state, we will import the useContext hook like we did above. We also need to import the UserContext from the file that we declared it in, and then we're good to go.

export default function Login () {
  const [userInfo, setUserInfo] = useContext(UserContext);

  return (
    <View>
      <Button
        title="Sign In"
        onPress={() => {
          setUserInfo(userInfo => ({
            signedIn: true
          }))
        }}
      />
    </View>
  )
}
Enter fullscreen mode Exit fullscreen mode

Above we have a simple Login component. We want to keep track of wether or not our user is signed in. We are bringing our UserContext in and setting it to a hook like we did previously. In our return statement we have a sign in button that will set the state of signedIn to true. We can make this function add, remove, or edit any values in our global state object, and all of these changes will be seen by all other components importing the UserContext. By using these hooks you can access state in any components that you'd like, without having to pass down props to every component connecting them. Hopefully this will be helpful when trying to find a simple way to read and manipulate global state in your apps.

Oldest comments (2)

Collapse
 
ashr81 profile image
Ashrith Reddy

I think it is better to use another custom hook that handles the importing of UserContext and useContext and which can accommodate more functionalities.

Code with custom hooks

Collapse
 
gabeklavans profile image
Gabriel Klavans

I just want you to know I spent hours looking for a solution like this... it’s so simple and digestible. Thank you!