React Context Api using TypeScript
Tags: react, typescript, beginners, tutorial
Published: 2022-06-29 20:59:44


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/msvwa283hg7yx8qr83yk.png)

### Introduction
React Context API provides a way to pass data down the component tree without passing props. It's useful when passing down data that is Global for a component tree. For example, current authenticated user, theme, and preferred language in a multi-lingual app. It helps avoid **props drilling** problem. 
We will build an app with several components where a global state of whether the user is logged in or not will be maintained. This state will be shared across components via context.

If you would prefer to follow this tutorial on YouTube it's available at the link below.

{% youtube nNIp10ADon4 %}

The final solution is available on GitHub
{% github https://github.com/tndungu/React-Context-Api-Project %}

### Prerequisites
This tutorial assumes you have some basic knowledge of using TypeScript with React. You may go through [TypeScript with React Tutorial](https://dev.to/tndungu/typescript-with-react-tutorial-3ah5) to get started.

### App Development: Step by Step Guide

To start a new typescript app, use the following command
- **yarn**:
```TypeScript
yarn create-react-app context-typescript-app --template typescript
```
- **npm**:
```TypeScript
npx create-react-app context-typescript-app --template typescript
```

cd into student-app and `yarn start` OR `npm start` if using npm. 

In the `src` folder, we will create a folder called `components`. Inside the folder lets create 3 simple components `Login`, `Home` and `Settings`. They will look as follows:

```TypeScript
//Login.tsx
export const Login = () => {
    return (
        <>
            <div className="pageLayout">
                <div>
                    <h3>Login</h3>
                </div>
                <div>
                    <button>Login</button>
                </div>
            </div>
        </>
    );
};
```
```TypeScript
//Home.tsx
export const Home = () => {

    return (
        <div className='pageLayout'>
            <div>
                <h3>Home Page</h3>
            </div>

            <div>
            </div>
        </div>
    )
}

```
```TypeScript
//Settings
export const Settings = () => {
    return (
        <div className='pageLayout'>
            <div>
                <h3>Settings</h3>
            </div>

            <div>
            </div>
        </div>
    )
}
```
Import the components in the `App.tsx` file. 

```TypeScript
import './App.css';
import { Home } from './components/Home';
import { Login } from './components/Login';
import { Settings } from './components/Settings';

function App() {

  return (
    <>
      <Login />
      <Home />
      <Settings />
    </>
  );
}

export default App;

```
Add the following Styles to the App.css file. 
```TypeScript
.App {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

.pageLayout{
  display: flex;
  align-items: center;
  justify-content:space-between;
  border: 0.1rem solid tomato;
  border-radius: 0.3rem;
  width: 50%;
  height: 100px;
  margin: 10px;
}
button{
  width: 100px;
  height: 25px;
  background-color: aqua;
  border-radius: 5px;
  cursor: pointer;
}

div{
  margin: 10px;
  min-width: 100px;
}
.title{
  max-width: 100px;
}
```
At this point, if you save all the files and run the app it should look like the below. 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o3ourcrl7si7dprzzskt.png)

### Create Context
In the `App.tsx`, we will create a context that will hold the state `loggedIn` which will be `true` if a user is logged in and `false` if a user is not logged in. 

```TypeScript
import './App.css';
import { Home } from './components/Home';
import { Login } from './components/Login';
import { Settings } from './components/Settings';
import { createContext, useState } from 'react'

export const LoginContext = createContext({ loggedIn: false, setLoggedIn: (loggedIn: false) => { } })

function App() {
  const [loggedIn, setLoggedIn] = useState<boolean>(false)

  return (
    <LoginContext.Provider value={{ loggedIn, setLoggedIn }}>
      <Login />
      <Home />
      <Settings />
    </LoginContext.Provider>
  );
}

export default App;
```
In the code above, `LoginContext` will have an object with 2 properties `loggedIn` which is a boolean value and `setLoggedIn` which is a function hook that is used to set the loggedIn value. 
The `LoginContext` object comes with Provider React Component that allows consuming components to subscribe to context changes. We will pass a value prop to `LoginContext.Provider`. This value will be propagated down the component tree to every component that subscribes to context changes. 

### useContext
We have created the context now it's time to consume it. In the components folder, let's add the simple component `DisplayLogin.tsx` which looks as follows. In addition, let's make the following changes to `Login.tsx`. 

```TypeScript
//DisplayLogin
export const DisplayLogin = () => {
  return (
    <div><h3>User is Logged in</h3></div>
  )
}

```
```TypeScript
//Login.tsx
import { useContext } from 'react'
import { LoginContext } from '../App'
import { DisplayLogin } from './DisplayLogin';

export const Login = () => {
    const { loggedIn, setLoggedIn } = useContext(LoginContext)

    return (
        <>
            <div className="pageLayout">
                <div>
                    <h3>Login</h3>
                </div>{!loggedIn &&
                    <DisplayLogin />
                }
                <div>
                    <button onClick={() => setLoggedIn(!loggedIn)}>Login</button>
                </div>
            </div>
        </>
    );
};

```
From the `Login.tsx` component above, we have used the `useContext` hook to subscribe and consume the LoginContext. This enables us to get the global variable within `Login.tsx` without passing props. If you run the app, it should display as follows. Once you click the button, the message 'User is Logged in' is displayed. 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ks0ow2m1sg71kzh393yo.png)
 

Lets subscribe in the `Home` and `Settings` components as well. The 2 components will now look as follows:

```TypeScript
//Home.tsx
import { useContext } from 'react'
import { LoginContext } from '../App'
import { DisplayLogin } from './DisplayLogin';

export const Home = () => {
    const { loggedIn, setLoggedIn } = useContext(LoginContext)
    return (
        <div className='pageLayout'>
            <div>
                <h3>Home Page</h3>
            </div>
            {!loggedIn &&
                    <DisplayLogin />
                }
            <div>
            </div>
        </div>
    )
}

```

```TypeScript
//Settings
import { useContext } from 'react'
import { LoginContext } from '../App'
import { DisplayLogin } from './DisplayLogin';

export const Settings = () => {
    const { loggedIn, setLoggedIn } = useContext(LoginContext)

    return (
        <div className='pageLayout'>
            <div>
                <h3>Settings</h3>
            </div>
            {!loggedIn &&
                <DisplayLogin />
            }
            <div>
            </div>
        </div>
    )
}
```
At this point, if you click the `Login` button, the message 'User is Logged in' is displayed on all components. This is because we have subscribed to the context of all the 3 components.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ozanu38gesmciq3dkaqc.png)

### Refactoring Context
The `useContext()` has been used in all components. This is not best practice since it means we're exposing the whole context in every component whereas it might not be necessary to do so. In addition, there are duplications in our code. So we need to move our Context code to its file. We can also create a custom hook to wrap `LoginContext.Provider`. The final code will look as follows:

```TypeScript
//App.tsx

import './App.css';
import { Home } from './components/Home';
import { Login } from './components/Login';
import { Settings } from './components/Settings';
import { LoginProvider } from './Context/LoginContext'

function App() {

  return (
    <LoginProvider>
      <Login />
      <Home />
      <Settings />
    </LoginProvider>
  );
}

export default App;

```

```TypeScript
// Context/LoginContext
import React, { useState, createContext } from "react";

interface LoginProviderProps{
  children: React.ReactNode
}

export const LoginContext = createContext({loggedIn: false,setLoggedIn: (loggedIn: boolean) => {}});

export const LoginProvider = ({ children }: LoginProviderProps) => {
  
  const [loggedIn, setLoggedIn] = useState(false);
  
  return (
    <LoginContext.Provider value={{ loggedIn,setLoggedIn }}>
      {children}
    </LoginContext.Provider>
  );
};

```

```TypeScript
//useLoginContext

import {useContext} from 'react'
import { LoginContext } from '../Context/LoginContext'

export const useLoginContext = () => {
  return useContext(LoginContext)
}

```

```TypeScript
//Home.tsx
import { useLoginContext } from './useLoginContext'

export const Home = () => {
    const { loggedIn } = useLoginContext()

    return (
        <div className='pageLayout'>
            <div>
                <h3>Home Page</h3>
            </div>
            {loggedIn &&
                    <div><h3>User is Logged in</h3></div>
                }
            <div>
            </div>
        </div>
    )
}

```

```TypeScript
//Login.tsx
import { useLoginContext } from "./useLoginContext";

export const Login = () => {
    const { loggedIn, setLoggedIn } = useLoginContext()

    return (
        <>
            <div className="pageLayout">
                <div>
                    <h3>Login</h3>
                </div>
                {loggedIn &&
                    <div><h3>User is Logged in</h3></div>
                }
                <div>
                    <button onClick={() => setLoggedIn(!loggedIn)}>{loggedIn ? 'Logout' : 'Login'}</button>
                </div>
            </div>
        </>
    );
};

```

```TypeScript
//Settings
import { useLoginContext } from './useLoginContext'

export const Settings = () => {
    const {loggedIn } = useLoginContext()
    
    return (
        <div className='pageLayout'>
            <div>
                <h3>Settings</h3>
            </div>
            {loggedIn &&
                    <div><h3>User is Logged in</h3></div>
                }
            <div>
            </div>
        </div>
    )
}

```

### Conclusion
Congratulations! You have gone through all that is required to create and use Context in React using TypeScript. Context API is a popular way of managing the global state for small to medium-level applications. For large-scale applications, REDUX might be a better way of managing the state. 
Feel free to comment below in case you need further assistance.