useContext() Hook : Let's consume  it
Tags: react, reactnative, javascript, hooks
Published: 2022-01-23 08:23:16

## 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.



```javascript
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>
  );
};
``` 

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](https://cdn.hashnode.com/res/hashnode/image/upload/v1642863016700/XDLkkAw7w.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.


```javascript

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>
  );
};
``` 

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](https://cdn.hashnode.com/res/hashnode/image/upload/v1642870565728/qc2gh8pa0.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` 


```javascript
 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>
``` 

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`.

```javascript
import React, { useContext} from 'react';
``` 

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

```javascript
export const UserInfoContext = React.createContext();
``` 

### Provide Context to Components

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


```javascript
 <UserInfoContext.Provider value={info}>
      <SafeAreaView style={styles.parent}>
        <Component1 />
      </SafeAreaView>
    </UserInfoContext.Provider>
``` 

### 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.


```javascript
 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>
  );
``` 


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](https://cdn.hashnode.com/res/hashnode/image/upload/v1642918602429/43VvdEDZS.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](https://twitter.com/yrajshekhar231)