Advanced ReactJS Tutorial: Master Context In A Few Simple Examples
Tags: webdev, javascript, react, learnwebdevelopment
Published: 2023-03-31 12:37:21

---
title: Advanced ReactJS Tutorial: Master Context In A Few Simple Examples
published: true
date: 2023-03-31 12:30:09 UTC
tags: webdevelopment,javascript,reactjs,learnwebdevelopment
canonical_url: 
---

![](https://cdn-images-1.medium.com/max/1024/1*3bqdJagRzZCQeOjf79_BAA.jpeg)
_ReactJS logo_

React Context transfers data between different levels of your application without "Prop Drilling." It provides a way to pass data through the components tree.

### Prop **Drilling**

To further understand react Context, we must first understand the problem it solves. Prop drilling occurs when we continue passing data to child components in an endless way, even though some of those components don't use it; they receive it to pass it to their children.

Let's take a typical example, a counter app.

```
export default function App() {
  const [counter, setCounter] = useState(0);

  return (
    <div>
      <AddOneButton setCounter={setCounter} />
      <Counter counter={counter} />
    </div>
  );
}
```

It has two children components, one to increase the count and another to show the current count.

```
const AddOneButton = ({setCounter}) => {
  return (
    <button onClick={() => setCounter((value) => value + 1)}>Add One</button>
  )
}

const Counter = ({counter}) => {
  return (
    <p>Count: {counter}</p>
  )
}
```

Now let us say we have a new component called `Container` that wraps the `AddOneButton`.

```
const Container = ({setCounter}) => {
  return <AddOneButton setCounter={setCounter} />
}
```

And now, inside the App we render the new `Container` component.

```
<Container setCounter={setCounter} />
```

Now it's clear that `Container` acutely does not need the `setCounter` function, we passed it just because `AddOneButton` needs it, and this what known as "Prop Drilling" this is why we need the Context Api.

### NOTE

In this case, we can mitigate the use of prop drilling by making the `Container` component a generic component and passing `AddOneButton` as a child.

```
const Container = ({children}) => {
  return (
    {children}
  )
}

export default function App() {
  const [counter, setCounter] = useState(0);

  return (
    <div>
      <Container>
        <AddOneButton setCounter={setCounter} />
      </Container>

      <Counter counter={counter} />
    </div>
  );
}
```

### Context with useState

now that we understand prop drilling, we can start using Context Api, but before that, we need to decide what way we will implement Context; there are mainly two ways either with `useState` or `useReducer` in this section, we will do it using `useState`, let us start by importing the required modules.

```
import {createContext, useContext} from "react";
```

Then we create the Context and its provider.

```
export const CounterContext = createContext(null);

export const CounterContextProvider = ({ children }) => (
  <CounterContext.Provider value={useState(0)}>
    {children}
  </CounterContext.Provider>
);
```

the `createContext` function initializes the Context, the provider will wrap our application (only the components inside the provider will have access to data), and because we are using context API we don't need to pass anything to `Container` or `Counter` components.

```
export default function App() {
  return (
    <CounterContextProvider>
      <Container />
      <Counter />
    </CounterContextProvider>
  );
}
```

Now to access the data, we shall use `useContext` hook.

```
const Container = () => {
  return <AddOneButton />;
};

const AddOneButton = () => {
  const [, setCounter] = useContext(CounterContext);
  return (
    <button onClick={() => setCounter((value) => value + 1)}>Add One</button>
  );
};

const Counter = () => {
  const [counter] = useContext(CounterContext);
  return <p>Count: {counter}</p>;
};
```

### Context with useReducer

Note: It's recommended to use `useReducer` if our state is more complex.

Let us start by importing the required modules.

```
import { createContext, useContext, useReducer } from "react";
```

Now let's create a reducer and plug it into our context data.

```
const reducer = (state, action) => {
  switch(action.type) {
    case "increment":
      return state + 1;
    default:
      return state
  }
}

export const CounterContext = createContext(null);

export const CounterContextProvider = ({ children }) => (
  <CounterContext.Provider value={useReducer(reducer, 0)}>
    {children}
  </CounterContext.Provider>
);
```

The hook returns a tuple, the first element is the value, and the second is the dispatch function.

```
const Container = () => {
  return <AddOneButton />;
};

const AddOneButton = () => {
  const [, dispatch] = useContext(CounterContext);
  return (
    <button onClick={() => dispatch({type: "increment"})}>Add One</button>
  );
};

const Counter = () => {
  const [counter] = useContext(CounterContext);
  return <p>Count: {counter}</p>;
};
```
And basically, that's how context Api works.