DEV Community

Cover image for useContext() Hook : Let's consume  it
Rajshekhar Yadav
Rajshekhar Yadav

Posted on • Originally published at yadavrajshekhar.hashnode.dev

useContext() Hook : Let's consume it

Introduction

In the previous part I have explained about the basic idea behind the useReducer() hooks. In this article I will try to explain about another useful hook useContext . We will discus about how to use what useContext is and how to use it. We will also discus about Context API.

The Problem

Consider a React-Native application having nested component and you have to pass the data to child at the bottom level. Let me explain the problem with a simple code sample.

const App = () => {
  const [info, SetUserInfo] = useState({
    name: 'Rajshekhar',
    about: 'Mobile Application Developer',
  });
  return (
    <SafeAreaView style={styles.parent}>
      <Component1 userInfo={info} />
    </SafeAreaView>
  );
};
const Component1 = props => {
  return (
    <View style={styles.sectionContainer}>
      <Text style={styles.sectionTitle}>
        This is Level 1. We don't need user info
      </Text>
      <Component2 userInfo={props.userInfo}></Component2>
    </View>
  );
};
const Component2 = props => {
  return (
    <View style={styles.sectionContainer}>
      <Text style={styles.sectionSubtitle}>
        This is Level 2. We don't need user info
      </Text>
      <Component3 userInfo={props.userInfo}></Component3>
    </View>
  );
};
const Component3 = props => {
  return (
    <View style={styles.sectionContainer}>
      <Text style={styles.sectionDescription}>
        This is Level 3. I need the user info.
      </Text>
      <Text style={styles.sectionDescription}>Hi {props.userInfo.name}!!</Text>
    </View>
  );
};
  };

  return (
    <SafeAreaView style={styles.parent}>
      <Component1 userName={name} />
    </SafeAreaView>
  );
};
Enter fullscreen mode Exit fullscreen mode

As you can see, We need to explicitly pass the props to even those components which do not even use it only to make the data available to the hierarchy below. We are maintaining the overhead of constantly passing the props data throughout the entire Hierarchy.

propDrill.png

I hope you are able to understand about the problem which I am trying to explain with the above code snippet. To solve this problem we have a rescuer Context API.

Context API

Context API provides a way to pass the data to component tree without passing the data to every level. Context API reduces the coupling between the non related components. For Implementing Context ApI we need below things

  • We have to create a Context, using React's createContext() method.
  • We will use the Provider in the high-level component to provide the Context Value.
  • We will then Consume the Context value using render props pattern.

export const UserInfoContext = React.createContext();
const App = () => {
  const [info, SetUserInfo] = useState({
    name: 'Rajshekhar',
    about: 'Mobile Application Developer',
  });
  return (
    <SafeAreaView style={styles.parent}>
      <UserInfoContext.Provider value={info}>
        <Component1 />
      </UserInfoContext.Provider>
    </SafeAreaView>
  );
};

const Component3 = () => {
  return (
    <UserInfoContext.Consumer>
      {userInfo => {
        return (
          <View style={styles.sectionContainer}>
            <Text style={styles.sectionDescription}>
              This is Level 3. I need the user info.
            </Text>
            <Text style={styles.sectionDescription}>Hi {userInfo.name}!!</Text>
          </View>
        );
      }}
    </UserInfoContext.Consumer>
  );
};
Enter fullscreen mode Exit fullscreen mode

Let me explain you the above code snippet.

  • I have created a UserInfoContext by calling React.createContext()
  • For providing the context , we have to wrap our parent component with UserInfoContext.Provider .
  • Then we have to provide the value that we want pass down the component tree on value prop
  • For consuming the provided information, we have to wrap our child (who need the data ) with UserInfoContext.Consumer component.

useContext.drawio.png

I found one problem with this approach. Suppose we have multiple context, then things go ugly when we consume the provided value from Provider

 return (
    <UserInfoContext.Consumer>
      {userInfo => {
        return (
          <NetworkContext.Consumer>
            {status => {
              return (
                <View style={styles.sectionContainer}>
                  <Text style={styles.sectionDescription}>
                    This is Level 3. I need the user info.
                  </Text>
                  <Text style={styles.sectionDescription}>
                    NetworkStatus : {status}
                  </Text>
                  <Text style={styles.sectionDescription}>
                    Hi {userInfo.name}!!
                  </Text>
                </View>
              );
            }}
          </NetworkContext.Consumer>
        );
      }}
    </UserInfoContext.Consumer>
Enter fullscreen mode Exit fullscreen mode

This code will work. But for the shake of readability, I personally don't like it.

I hope I am able to explain the basic idea of Context API .

useContext()

As we discussed about the Context API. useContext is another way of consuming context. It accepts a context object and returns the current context value for the that context.

Declaring the useContext()

Import the useContext() package from react.

import React, { useContext} from 'react';
Enter fullscreen mode Exit fullscreen mode

Creating a context

We can create a context by using React.createContext()

export const UserInfoContext = React.createContext();
Enter fullscreen mode Exit fullscreen mode

Provide Context to Components

For providing the value to our component. We have to wrap our component with Provider Component.

 <UserInfoContext.Provider value={info}>
      <SafeAreaView style={styles.parent}>
        <Component1 />
      </SafeAreaView>
    </UserInfoContext.Provider>
Enter fullscreen mode Exit fullscreen mode

Consuming the context

Instead of using render props, we can pass the entire context object to React.useContext() to consume context at the top of our component.

 const userInfo = useContext(UserInfoContext);
  return (
    <View style={styles.sectionContainer}>
      <Text style={styles.sectionDescription}>
        This is Level 3. I need the user info.
      </Text>
      <Text style={styles.sectionDescription}>Hi {userInfo.name}!!</Text>
    </View>
  );
Enter fullscreen mode Exit fullscreen mode

Don’t forget that the argument to useContext must be the context object itself:

useContext(MyContext.Consumer) ❌
useContext(MyContext.Provider) ❌
useContext(MyContext) βœ…

consume _me.drawio.png

Conclusion

Let's take down key points about useContext() Hook.

  • It removes the overhead of passing the data via props through a nested component. In a simple word, if you want the data just consume it.
  • We can follow three simple steps to use it.
    • Create a context with the help of React.createContext() .
    • Wrap the parent component with YourContext.Provider component and pass the value
    • Consume it wherever it is needed with the useContext(YourContext) .

Thanks for reading this article. I have tried to explain my understanding about useContext hooks. Feel free to add suggestion. Let's connect on Twitter

Top comments (1)

Collapse
 
fkranenburg profile image
Ferry Kranenburg

Thank you so much for this great explanation! I'm currently learning React (Native) and this helps a lot. Thanks again.