Data is one of the essences of any application. For a web app to be functional it requires the data to flow from one part of the application to another. From a React or Angular application's perspective, for an app to be up and running data needs to be passed from one component to another.
In this tutorial, you'll learn about the Context API which is used for passing or sharing data across components in React.js. It provides a way to pass data across the component tree. This is extremely useful when we have several components down the component tree.
What is Context API
From the official documentation,
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
Let's break it down with the help of an example. Imagine a component tree structure having 5 components. Data from the parent component is only required at the 5th component. In that case, you'll be required to pass data from each component to another as props until it reaches the last component.
This whole process is quite tedious and requires props
to be passed at each level even though it's not required at those levels. Using the Context API you can share data among a tree of components without passing it as props
at each level.
Why Use It?
Using Context API reduces the tedious process of passing the required data as props to each level. Although it makes reusing components a bit difficult, still it does the job.
Seeing it in Demo
Now let's see Context API in action. We'll start by creating a React app and make it functional by passing data as props. And then we'll see how and where to use Context API for sharing the data.
Creating React App
We'll be making use of create-react-app
to create our React project. So, first, you need to install create-react-app
using npm
.
npm install -g create-react-app
Once done you can use it to create your react app.
npx create-react-app react-context-app
The above command creates a boilerplate code for you to get started.
You can navigate to the react-context-app
folder and start the react app using npm start
.
You will have the default boilerplate react application running at http://localhost:3000/.
For the sake of this tutorial demo, we'll require a couple of components. So, let's create components to create a component tree.
Creating Different Level components
By default inside the src
folder, we have the App.js
file. Here App
is the default component that is being rendered inside the index.js
file.
We'll be making use of Bootstrap
to design our React app. So, let's install React Bootstrap to our app using npm
.
npm install react-bootstrap bootstrap
Once React bootstrap is installed you can import the required components and use them in your React components.
Add the following bootstrap css
import in index.js
to install bootstrap globally inside the app.
import 'bootstrap/dist/css/bootstrap.min.css';
Let's start by creating an Accordion
in our React app. First, we'll create a component called Dashboard
which will be using the Accordion
bootstrap component.
Dashboard component
Inside the src
folder create a folder called components
. Inside components
create a folder called dashboard
and inside it create a file called dashboard.js
. Import the accordion
in dashboard.js
and use it as shown:
import Accordion from 'react-bootstrap/Accordion';
const Dashboard = () => {
return (
<Accordion defaultActiveKey="0">
<Accordion.Item eventKey="0">
<Accordion.Header>Accordion Item #1</Accordion.Header>
<Accordion.Body>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</Accordion.Body>
</Accordion.Item>
<Accordion.Item eventKey="1">
<Accordion.Header>Accordion Item #2</Accordion.Header>
<Accordion.Body>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</Accordion.Body>
</Accordion.Item>
</Accordion>
);
}
export default Dashboard;
Save the changes and reload the app and you will be able to see the accordion inside the react app.
Tab Component
Inside the accordion, we'll show the data in a tab format. So, let's create a tab component. Create a folder called tab
inside src/components
and create a file called tab.js
. Here is how it looks:
import Tab from 'react-bootstrap/Tab';
import Tabs from 'react-bootstrap/Tabs';
const MyTab = () => {
return (
<Tabs
defaultActiveKey="employee"
id="uncontrolled-tab-example"
className="mb-3"
>
<Tab eventKey="employee" title="Employee">
</Tab>
<Tab eventKey="profile" title="Profile">
</Tab>
</Tabs>
);
}
export default MyTab;
Include the Tab
component inside the accordion body.
import Accordion from 'react-bootstrap/Accordion';
import MyTab from '../tab/tab';
const Dashboard = () => {
return (
<Accordion defaultActiveKey="0">
<Accordion.Item eventKey="0">
<Accordion.Header>Accordion Item #1</Accordion.Header>
<Accordion.Body>
<MyTab />
</Accordion.Body>
</Accordion.Item>
<Accordion.Item eventKey="1">
<Accordion.Header>Accordion Item #2</Accordion.Header>
<Accordion.Body>
<MyTab />
</Accordion.Body>
</Accordion.Item>
</Accordion>
);
}
export default Dashboard;
Now let's create one more component called List
which will be nested inside each of the Tab
.
List Component
Inside the src/components/list
create a file called list.js
. Import the ListGroup
component and create the List component. Here is how it looks:
import ListGroup from 'react-bootstrap/ListGroup';
const List = () => {
return (
<ListGroup>
<ListGroup.Item>Cras justo odio</ListGroup.Item>
<ListGroup.Item>Dapibus ac facilisis in</ListGroup.Item>
<ListGroup.Item>Morbi leo risus</ListGroup.Item>
<ListGroup.Item>Porta ac consectetur ac</ListGroup.Item>
<ListGroup.Item>Vestibulum at eros</ListGroup.Item>
</ListGroup>
);
}
export default List;
Include the List
component inside the Tab
component. Here is how the tab.js
looks:
import Tab from 'react-bootstrap/Tab';
import Tabs from 'react-bootstrap/Tabs';
import List from '../list/list';
const MyTab = () => {
return (
<Tabs
defaultActiveKey="employee"
id="uncontrolled-tab-example"
className="mb-3"
>
<Tab eventKey="employee" title="Employee">
<List />
</Tab>
<Tab eventKey="profile" title="Profile">
<List />
</Tab>
</Tabs>
);
}
export default MyTab;
Save the above changes and reload the app. You will be able to see a couple of accordions and when clicking the accordion, you’ll see a set of tabs. Inside the tabs, a list of items is shown.
Let's see how you can pass some data from Dashboard
to List
Sharing Data Using Props
Now on clicking the accordion, let's say the first item you want to show in the list group component is the clicked accordion name. In order to do that you need to pass that data as props
to its child components.
We have three components, Dashboard
, Tab
, and List
. Let's first pass the accordion name as accordionData
props from the Dashboard
to the Tab
component.
Inside the Dashboard
component you can pass the data as shown :
<MyTab accordionData="Item #1" />
You can access this data inside the Tab
component using props
as shown and pass it to the List
component. Here is how the Tab
component looks:
import Tab from 'react-bootstrap/Tab';
import Tabs from 'react-bootstrap/Tabs';
import List from '../list/list';
const MyTab = (props) => {
return (
<Tabs
defaultActiveKey="employee"
id="uncontrolled-tab-example"
className="mb-3"
>
<Tab eventKey="employee" title="Employee">
<List accordionData={props.accordionData} />
</Tab>
<Tab eventKey="profile" title="Profile">
<List accordionData={props.accordionData} />
</Tab>
</Tabs>
);
}
export default MyTab;
Tab component has no use of accordionData except to pass it along to the List component.
Similarly, you can access the props
inside the List
component and render the name of the accordion as the first item in the list. Here is how the list.js
file looks:
import ListGroup from 'react-bootstrap/ListGroup';
const List = (props) => {
return (
<ListGroup>
<ListGroup.Item>{props.accordionData}</ListGroup.Item>
<ListGroup.Item>Dapibus ac facilisis in</ListGroup.Item>
<ListGroup.Item>Morbi leo risus</ListGroup.Item>
<ListGroup.Item>Porta ac consectetur ac</ListGroup.Item>
<ListGroup.Item>Vestibulum at eros</ListGroup.Item>
</ListGroup>
);
}
export default List;
Save the above changes and reload the app. On clicking the accordion you'll be able to see the name of the accordion as the first item in the list.
For showing the accordion data we are passing the name of the accordion from the Dashboard
component to the Tab
component and from Tab
to List
, even though there is no use of accordionData
inside the Tab
component.
Let's see how Context API reduces the effort of passing data from each component level in a component tree.
Using Context API for Data sharing
We'll create a context from the Dashboard component. In order to do so you need to use React.createContext
in the Dashboard component as shown:
const default_accordion_name = "Item #1";
export const AccordionContext = React.createContext(default_accordion_name);
On click of the accordion, the name will change, so we need a state variable to keep track of it. Let's define it as shown:
const [accordionData, setAccordionData] = useState(default_accordion_name);
const handleOnClick = (name) => {
setAccordionData(name);
}
On click of the accordion, we also need to add the onClick
handler.
onClick={() => handleOnClick('Item #1')}
To use the AccordionContext
you need to contain the Dashboard component inside the AccordionContext
as shown:
<AccordionContext.Provider value={{ value: accordionData }}>
<Accordion defaultActiveKey="0">
<Accordion.Item eventKey="0" onClick={() => handleOnClick('Item #1')}>
<Accordion.Header>Accordion Item #1</Accordion.Header>
<Accordion.Body>
<MyTab accordionData="Item #1" />
</Accordion.Body>
</Accordion.Item>
<Accordion.Item eventKey="1" onClick={ () => handleOnClick('Item #2')}>
<Accordion.Header>Accordion Item #2</Accordion.Header>
<Accordion.Body>
<MyTab accordionData="Item #2" />
</Accordion.Body>
</Accordion.Item>
</Accordion>
</AccordionContext.Provider >
Here is the complete dashboard.js
file:
import { useState } from 'react';
import Accordion from 'react-bootstrap/Accordion';
import MyTab from '../tab/tab';
import React from 'react';
const default_accordion_name = "Item #1";
export const AccordionContext = React.createContext(default_accordion_name);
export const Dashboard = () => {
const [accordionData, setAccordionData] = useState(default_accordion_name);
const handleOnClick = (name) => {
setAccordionData(name);
}
return (
<AccordionContext.Provider value={{ value: accordionData }}>
<Accordion defaultActiveKey="0">
<Accordion.Item eventKey="0" onClick={() => handleOnClick('Item #1')}>
<Accordion.Header>Accordion Item #1</Accordion.Header>
<Accordion.Body>
<MyTab accordionData="Item #1" />
</Accordion.Body>
</Accordion.Item>
<Accordion.Item eventKey="1" onClick={ () => handleOnClick('Item #2')}>
<Accordion.Header>Accordion Item #2</Accordion.Header>
<Accordion.Body>
<MyTab accordionData="Item #2" />
</Accordion.Body>
</Accordion.Item>
</Accordion>
</AccordionContext.Provider >
);
}
As you might have noticed in the code above, we are passing the value to the AccordionContext
as:
<AccordionContext.Provider value={{ value: accordionData }}>
Now, this value can be accessed anywhere inside the component tree under the Dashboard
component. So don't need to pass unnecessary data to every component level.
To access the data passed in Context, you need to make use of the useContext
hook.
const accordionData = useContext(AccordionContext);
where AccordionContext
is imported from the Dashboard
component. Here is the modified list.js
file which shows how to access data from Context.
import ListGroup from 'react-bootstrap/ListGroup';
import {AccordionContext} from '../dashboard/dashboard'
import { useContext } from 'react';
const List = (props) => {
const accordionData = useContext(AccordionContext);
return (
<ListGroup>
<ListGroup.Item>{accordionData.value}</ListGroup.Item>
<ListGroup.Item>Dapibus ac facilisis in</ListGroup.Item>
<ListGroup.Item>Morbi leo risus</ListGroup.Item>
<ListGroup.Item>Porta ac consectetur ac</ListGroup.Item>
<ListGroup.Item>Vestibulum at eros</ListGroup.Item>
</ListGroup>
);
}
export default List;
Save the above changes and reload the app. On click of each accordion, its name will show as first entry in the respective list group.
Final Thoughts
In this tutorial, you learned what Context API is and what its use is. You saw how it reduces the effort of passing props down to each component level even though it's not required in those components.
Hope you liked this tutorial. Source code from this tutorial can be found at GitHub.