MediumIntegrating The Context Api in react | by Okafor Johnson | Medium
Sitemap
Okafor Johnson

Okafor Johnson

I’m a web developer . My expertise lies within front-end web apps, and the main languages in my tech stack are JavaScript, React, Vue and of course HTML/CSS.

Integrating The Context Api in react

TABLE OF CONTENT

8 min readFeb 7, 2023

--

  1. Requirements
  2. Getting started
  3. Creating components
  4. Building the project
  5. Consuming the context
  6. Conclusion

The Context API helps to share data between components which you can’t easily share with props. Data is shared from parents to children nested deep down the component tree directly without prop drilling(passing prop between corresponding components). It is mostly used to create global variables e.g theme, Auth and UserId data.

In this article we would put our knowledge to learn how to create and consume the Context API in React by developing a fake userAuthContext to always carry out a fake authentication.

Don’t be borthered if you have little or no knowledge of some react content that includes:

  • useContext Hook
  • useState Hook
  • React Router
  • useRef Hook
  • Custom Hooks
  • Error Boundary

Requirements

Here are some necessity needed to complete this project

  • Node version 14+ and NPM version 5.6+ installed
  • Command Line Interface (I will be using PowerShell)
  • Basic JavaScript Knowledge
  • Basic Bash Scripts Knowledge
  • An IDE (preferably VsCode)
  • Strong Internet connection

Getting started

Create a react application

open your terminal and input

npx create-react-app user-auth-app

The user-auth-app being the name of the folder your react application will be saved, you could change it to whatever name you want.

Now our React app is created, navigate to the folder,

cd user-auth-app
code.

The React app comes with a hierarchy of files and folders, follow this link to get more understanding of this hierarchy, here.

then,

npm start

Creating the components

Components are independent and reusable bits of code. They serve the same purpose as JavaScript functions but work in isolation and return HTML.

Building the Project

Build the parent component [App.js]

Firstly, in the App.js file, we'll create the context for current the user using createContext . So we will be importing the context API and useState for local state management

import { createContext, useContext, useState } from 'react'

createContext lets you create a context that components can provide or read.

In the App.js file,

//App.js
import { createContext, useContext, useState } from 'react'

const UserAuthentication = {
isAuthenticated: false
} // default value for users

const Authenticate = createContext(UserAuthentication) // creates a context object with a default value passed(global state)

After creating a context, next, we’ll cover the component tree with the context.provider and a value prop so every child component in the tree would have access to the context.

export function App() {

return (
<Authenticate.Provider value={UserAuthentication}>

<!---- Child components go here --->

</Authenticate.Provider>
)
}

Now, the context can be consumed by any component down the tree. Next, we’ll be creating a state for anonymous users using useState.

useState is a React Hook that lets you add a state variable to your component. useState is used in this app component to create a local state for current users before users sign in.


import { createContext, useContext, useState } from 'react'

const UserAuthentication = {
isAuthenticated: false
}

const Authenticate = createContext(UserAuthentication)
export function App() {

const [user, setUser] = useState(null) // sets the state of anonymous users
return (
<Authenticate.Provider value={UserAuthentication}>

</Authenticate.Provider>
)
}

Create all other pages/components needed

In the src(folder), create a folder for components and create these component files inside as shown below:

Image components
image components

Since page routing is needed in this project, the react-router-dom would be installed to make routing to different components available.

Get Okafor Johnson’s stories in your inbox

Join Medium for free to get updates from this writer.

In order to install the react-router-dom, run this code on your Vscode terminal

npm i react-router-dom

React Router DOM is an npm package that enables you to implement dynamic routing in a web app.

Now we can access the components and hooks that come with it by importing them where they are needed.

Creating Routes

At the top of your fileApp.js , we'll import these components from react-router-dom

import { BrowserRouter, Route, Routes } from 'react-router-dom'

Afterward, create your routes in the App.js file.

import { createContext, useContext, useState } from 'react'
import { BrowserRouter, Route, Routes } from 'react-router-dom'

export function App() {

const [user, setUser] = useState(null)

return (

<Authenticate.Provider value={UserAuthentication}>
<BrowserRouter>
<main>
<Routes>
<Route path='/' element={<Home setUser={setUser} user={user}/>}>
<Route path='/verification-message'/>
</Route>
<Route path='/login' element={<Login setUser={setUser}/>}/>
<Route path='/loading' element={<Loading/>}/>
<Route path='/verify' element={<Verify />}/>
<Route path='*' element={<PageNotFound/>}/>
</Routes>
</main>
</BrowserRouter>
</Authenticate.Provider>

)
}

Creating an Error Boundary

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed.

To install, run this code on your terminal in vscode

npm i react-error-boundary

Then, in the App.js import this at the tope:

// imports the ErrorBoundary components
import {ErrorBoundary} from 'react-error-boundary'

Now wrap the component tree with the ErrorBoundary component

// App.js
import { createContext, useContext, useState } from 'react'
import { BrowserRouter, Route, Routes } from 'react-router-dom'
import {ErrorBoundary} from 'react-error-boundary'

const UserAuthentication = {
isAuthenticated: false
}

const Authenticate = createContext(UserAuthentication)
export function App() {

const [user, setUser] = useState(null) // sets the state of anonymous users
return (
<ErrorBoundary FallbackComponent={ErrorBoundaryPage}>
<Authenticate.Provider value={UserAuthentication}>
<BrowserRouter>
<main>
<Routes>
<Route path='/' element={<Home setUser={setUser} user={user}/>}>
<Route path='/verification-message'/>
</Route>
<Route path='/login' element={<Login setUser={setUser}/>}/>
<Route path='/loading' element={<Loading/>}/>
<Route path='/verify' element={<Verify />}/>
<Route path='*' element={<PageNotFound/>}/>
</Routes>
</main>
</BrowserRouter>
</Authenticate.Provider>
</ErrorBoundary>
)
}

In the ErrorBoundaryPage.js file, we'll create the FallbackComponent

import {useState} from 'react'
import {Link} from "react-router-dom" // component for routing

export default function Error({error, resetErrorBoundary}) {
[error, resetErrorBoundary] = useState(false)
return (
<div className='error_bg'>

<h2>{error.message}</h2>
<button onClick={()=>resetErrorBoundary(error => !error)}> TRY AGAIN</button>
{error ? <Link to='/'>Go Back Home </Link>: null}

</div>
)
}

Create an hook for SEO

The SEO rule will be to give each page its unique title, so, in the useDocumentTitle.js ,

import {useEffect, useRef} from 'react'

export default function useDocumentTitle(title, prevailOnUnmount = false) {
const defaultTitle = useRef(document.title);

useEffect(() => {
document.title = title;
}, [title]);

useEffect(() => () => {
if (!prevailOnUnmount) {
document.title = defaultTitle.current;
}
}, [])
}

useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

Create the Loading, Navigation and Error-404 components

In the Loading.js file, the page that displays when navigating to other pages. This is required so the page navigated to load its content before the display.

export default function Loading() {
return <div className='loading'>
<img src="loader.gif" alt="LOADING"/>
</div>
}

Furthermore, In the Navigation.js file, we'll create the navigation component, which is used by other components.

import {Link} from 'react-router-dom'
function Navigation() {
return (
<nav>
<Link className="link" to="/">Home</Link>
<Link className="link" to="/verify">Verify account</Link>
</nav>
)
}

export default Navigation

In the PageNotFound.js file, the page for routes that are not defined will be created so a blank UI is not displayed to users.

import {Link} from 'react-router-dom'
export default function Page404 (){
return (
<div className='error_bg'>
<Link to='/'>Go Back Home </Link>
</div>
)
}

Create an Homepage

In the Home.js file,we'll be importing useEffect from React

import { useEffect } from "react"

useEffect is a React Hook that lets you perform a side effect in function components. learn more about useEffect here.

In this app, users are redirected to the login page to sign in before accessing the home page. Such redirects can be made available by importing useNavigate from react-router-dom

import { useEffect } from "react"
import { useNavigate } from "react-router-dom"

Users that are not logged in would be redirected to the login page using the useNavigate hook

The home component

In the Home component, we'll be creating a log-out button, so logged-in users can leave the app.

import Navigation from "./Navigation"
import { useNavigate } from "react-router-dom"
import useDocumentTitle from "./useDocumentTitle"
import { useEffect } from "react"
const Home = ({user, setUser})=>{
const navigate = useNavigate()
useEffect(()=>{
if (!user) {
navigate('/login') // navigate to login page if no user
}
}, [user])
// log out btn function
const handleLogout = () => {
setUser(null);
navigate('/login')
}
console.log(user)

useDocumentTitle('Home - fakeuserAuth') // SEO for title in Home page

return (
<div>
<Navigation />
<h1>Hello {user? user.toUpperCase(): user}</h1>
<div className="home-btns">
<button onClick={()=>{navigate('/verify')}}>
Click to check if account is verified
</button>
<button onClick={handleLogout}>
Logout
</button>
</div>

</div>
)
}

export default Home // makes the Home component available for all use in other components

Creating the Login page

In the Login.js file, we'll import {useNavigate} from react-router-dom so users can navigate back to the Home page after filling in their details.

import { useNavigate } from "react-router-dom"
import useDocumentTitle from "./useDocumentTitle"

// Login component
const Login = ({setUser})=> {
useDocumentTitle('Login - fakeuserAuth') // SEO for title in Login page
const navigate = useNavigate()
// get user details onSubmit
const getUser = (e)=> {
e.preventDefault()
const user = e.target
setUser(user.username.value)
if ((user.username.value && user.password.value) !== "") {
setTimeout(()=>{
navigate('/') // navigate to home page if details are correct
},5000)
navigate('/loading') // display loading component for 5 secs
}
}
return (
<form onSubmit={getUser}>
<input type="text" name="username" placeholder="Enter username"/>
<br/>
<input type="password" name="password" placeholder="Enter password"/>
<br/>
<button>Sign In</button>
</form>
)
}


export default Login // make login component available for use on other components

On signing In, the username is passed as a prop to the parent component to be used in a greeting message on the Home page.

Consuming the content

In theApp.js component, all required components will be imported [ alongside other components you created yourself ]

import { BrowserRouter, Route, Routes } from 'react-router-dom'
import ErrorBoundaryPage from './components/ErrorBoundaryPage'
import './App.css'
import Loading from './components/Loading'
import Login from './components/Login'
import Home from './components/Home'
import Navigation from './components/Navigation'
import PageNotFound from './components/PageNotFound'
import {ErrorBoundary} from 'react-error-boundary'
import { createContext, useContext, useState } from 'react'

To consume the API , useContext is called which accepts the object that was created using createContext and returns the current value of that context.

// App.js
export function Verify (){

const value = useContext(Authenticate)
const [verified, isVerified] = useState(value)
const UserVerification = ()=> {
if (!verified.isAuthenticated) {
isVerified({isAuthenticated: true})
console.log(Authenticate)
} else {
isVerified({isAuthenticated: false})
}
}
if (verified.isAuthenticated) {
return <div className='verified'>
<Navigation />
<img src='success-green-check-mark-icon.png' alt='checkmark' />
</div>
}

return (
<div>
<Navigation />
<div className='verify'>
<button className="verify-btn" onClick={UserVerification}>
Verify
</button>
</div>
</div>
)

}

How the App.js file looks in the end,

import { BrowserRouter, Route, Routes } from 'react-router-dom'
import ErrorBoundaryPage from './components/ErrorBoundaryPage'
import './App.css'
import Loading from './components/Loading'
import Login from './components/Login'
import Home from './components/Home'
import Navigation from './components/Navigation'
import PageNotFound from './components/PageNotFound'
import {ErrorBoundary} from 'react-error-boundary'
import { createContext, useContext, useState } from 'react'

const UserAuthentication = {
isAuthenticated: false
}

const Authenticate = createContext(UserAuthentication)
export function App() {

const [user, setUser] = useState(null) // sets the state of anonymous users
return (
<ErrorBoundary FallbackComponent={ErrorBoundaryPage}>
<Authenticate.Provider value={UserAuthentication}>
<BrowserRouter>
<main>
<Routes>
<Route path='/' element={<Home setUser={setUser} user={user}/>}>
<Route path='/verification-message'/>
</Route>
<Route path='/login' element={<Login setUser={setUser}/>}/>
<Route path='/loading' element={<Loading/>}/>
<Route path='/verify' element={<Verify />}/>
<Route path='*' element={<PageNotFound/>}/>
</Routes>
</main>
</BrowserRouter>
</Authenticate.Provider>
</ErrorBoundary>
)
}

export function Verify (){

const value = useContext(Authenticate)
const [verified, isVerified] = useState(value)
const UserVerification = ()=> {
if (!verified.isAuthenticated) {
isVerified({isAuthenticated: true})
console.log(Authenticate)
} else {
isVerified({isAuthenticated: false})
}
}
if (verified.isAuthenticated) {
return <div className='verified'>
<Navigation />
<img src='success-green-check-mark-icon.png' alt='checkmark' />
</div>
}

return (
<div>
<Navigation />
<div className='verify'>
<button className="verify-btn" onClick={UserVerification}>
Verify
</button>
</div>
</div>
)

}

Conclusion

I hope you enjoyed reading this article, if it doesn’t make much sense the first time, go over it again and ensure you practice it while reading. Trust me, you will get a hang of it. Like Henry Ford would say, “There are no big problems, just small ones and that’s how you should see it”. you learned some of the concepts that were covered in it, if not you can go over it, and you might consider reading more on each topics talked about.

I’m open to hearing your feedback on what I could improve. This is my first blog but I promise it wouldn’t be my last. I intend to document my experiences as a Tech Newbie.

--

Okafor Johnson
Okafor Johnson

Written by Okafor Johnson

I’m a web developer . My expertise lies within front-end web apps, and the main languages in my tech stack are JavaScript, React, Vue and of course HTML/CSS.