DEV Community

Cover image for Struggling With Context API ? You Are Not Alone.
Talabi Ayomide
Talabi Ayomide

Posted on • Edited on

Struggling With Context API ? You Are Not Alone.

State is an essential part of our React application, hence, the need to pass to different components. state/data is passed top-down (parent to child) via props. This is called PROP DRILLING.
Prop drilling

This method becomes complex as the application grows and as many components require different props.
Things can get messy in a twinkle of an eye.

Context provides a way to share values like these between components without having to pass a prop through every level of the tree.

In this guide, we would talk about context API, and its usage and build a mini-project ( a search application ) with it.
Let's dive in.

Context is designed to share data that can be considered global for a tree of React components, such as the current authenticated user, theme, etc.

I am guessing your editor is already set up.

Set up Context API

First, we have to create a file called ResultContext.js (feel free to name it whatever you want) and import the required hooks.

import React , { useContext , useState , createContext } from "react"

  • Create Context
const ResultContext = createContext()
Enter fullscreen mode Exit fullscreen mode
  • Create a "Provider" and add {children} as a prop
export const ResultContextProvider = ( {children }) => {
//state for results
const [results , setResults ] = useState([]);
//state for search Term
const [searchTerm , setSearchTerm ] = useState('Elon Musk');

//create a function to fetch data

const getResults = async () => {
    const options = {
        method: 'GET',
        headers: {
            'X-API-Key': process.env.REACT_APP_API_KEY,
        }
    };

    const response = await fetch('https://google
search3.p.rapidapi.com/api/v1/search', options)

    const data = await response.json();
    //set results to the results gotten from data fetched
    setResults(data.results)
}
Enter fullscreen mode Exit fullscreen mode
  • Return Context.Provider inside the previously created Provider and set value to the props to be passed.
return (
    <ResultContext.Provider value= { { getResults , results , searchTerm , setSearchTerm } } >
        {children}
    </ResultContext.Provider>
)
}
Enter fullscreen mode Exit fullscreen mode

We are done with setting up our context file. In summary:

  1. We created context using the createContext() hook.
  2. We created A "provider" and passed {children} as a prop and returns ResultContext.Provider.
  3. We fetched data and set the results state to the data fetched.
  4. We returned a ResultContext.Provider and set value to the states we want to pass as props into other components. Whatever we pass into the value prop will be available throughout our app.

Wrap the App component with the Provider

import React from 'react';
import App from './App';
import { ResultContextProvider } from
'./context/ResultContextProvider';
import { createRoot } from 'react-dom/client';
const container = document.getElementById('root');
const root = createRoot(container);

//wrap <App /> with Provider to make state available through app
root.render(
     <ResultContextProvider>
          <Router>
               <App />
          </Router>
     </ResultContextProvider>
);
Enter fullscreen mode Exit fullscreen mode

Consume the props

Now the state/Props are available throughout the App, we now need to consume them.

  1. Import the required Hooks
    import React, { useEffect, useContext } from 'react'
    The useContext hook is used to get the props from the context.

  2. Import the context
    import { ResultContext } from '../context/ResultContext'

  3. Get the props from the context using useContext

//component for search
import React, { useEffect, useState, useContext } from 'react';
import { ResultContext } from '../context/ResultContext';

const Search = () => {
  //get prop from context
  const { setSearchTerm } = useContext(ResultContext);
  const [text, setText] = useState('');

  //change the value of text throughout our app
  useEffect(() => {
    if (text) {
      setSearchTerm(text)
    }
  }, [text]);

  return (
    <div>
    <div>
      <input
        value={text}
        type="text"
        onChange={(e) => setText(e.target.value)}
      />  

    {text !== '' && (
      <button type="button" onClick={() => setText('')}>x</button>
    )}
    </div>
  )
}

export default Search;
Enter fullscreen mode Exit fullscreen mode
//component displaying result
import React, { useEffect, useContext } from 'react'
import { useResultContext } from '../context/ResultContext';


const News = () => {
  const { results, getResults, searchTerm } =  useContext(ResultContext);

  useEffect(() => {
    if (searchTerm !== '') {
      getResults();
  }
}, [searchTerm]);


return (
  <div>
  {results?.map(({ link, title, description }, index) => (
  <div key={index}>
    <a href={link} target="_blank" rel="noreferrer">
      <p>{link.length > 30 ? link.substring(0, 30) : link}</p>
      <p >{title}</p>
      <p>{description}</p>
    </a>
  </div>
  ))} 
  </div>
)
}
export default News
Enter fullscreen mode Exit fullscreen mode

Conclusion

The main takeaways from this article include the following:
The React Context API is designed for prop drilling

This example is fairly simple and I hope you’ve been able to understand how to handle State in React using the context API.

Top comments (6)

Collapse
 
ndom91 profile image
Nico Domino • Edited

Just a tip, label the files you're describing with the name of the file, it makes the whole post much easier to follow.

I'm not sure if dev.to supports it, but with some markdown engines, you can do something liek this, for example:

` ``js title="./context/ReactContextProvider.js"
code here
` ``
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ayo_dev profile image
Talabi Ayomide

Thank you Nico.

Collapse
 
ivan_jrmc profile image
Ivan Jeremic

I use often multiple contexts and sometimes I need to share the same setter to both, how do you avoid running the setter rerendering both trees?

Collapse
 
biomathcode profile image
Pratik sharma
Collapse
 
ivan_jrmc profile image
Ivan Jeremic

I think the author of this post needs this article, I understand the problem.

Collapse
 
yongchanghe profile image
Yongchang He

The swimming pic is really amazing😂!