How to use context API in React with TypeScript in Vite
After reading this article, you will be able to use Context API in React with TypeScript in Vite
What is Context API?
The Context API is a feature in React, a popular JavaScript library for building user interfaces, that allows one to manage and share the state between components without passing data through props at every level of the component tree. It's a way to create a global or shared state that can be accessed by any component in one's application, making it a useful tool for managing application-wide data.
File Structure
Here's a basic file structure for a Vite project with the Context API for a React application in Vite:
my-context-app/
├── src/
│ ├── components/
│ │ ├── App.tsx
│ │ ├── ChildComponent.tsx
│ ├── context/
│ │ ├── MyContext.tsx
│ ├── main.tsx
│ ├── App.css
│ ├── index.html
In this structure:
src/: This directory contains the main source code for my Vite project.
components/: This directory is where I place my React components.
App.tsx: The root component of my application.
ChildComponent.tsx: A child component that consumes the context.
context/: This directory is for context-related code.
- MyContext.tsx: This file defines and exports my context using the
createContext
function and possibly theProvider
component.
- MyContext.tsx: This file defines and exports my context using the
main.tsx: This is the entry point for my Vite application, where I import and render the root component (
App
) into the DOM.App.css: My application's CSS file for styling.
index.html: The HTML template for my application.
Context API setup in MyContext.tsx
Here's a sample MyContext.tsx
file in Vite:
import React,{ createContext, useContext,ReactNode,Dispatch,SetStateAction} from 'react';
export interface GlobalContextTypes {
target: string;
options: string[];
setTarget: Dispatch<SetStateAction<string>>;
changeTarget: (name: string) => void;
}
interface AppContextProps {
children: ReactNode;
}
const GlobalContext = createContext<GlobalContextTypes | undefined>(undefined);
export const useGlobalContext=()=>useContext(GlobalContext_;
const AppContext=React.FC<AppContextProps>=({children})=>{
const [target,setTarget]=useState<string>("Home");
const options:string[]=["Home","Street"];
const changeTarget=(name:string)=>{
setTarget(name);
}
return (
<GlobalContext.Provider
value={{
target,
options,
setTarget,
changeTarget,
}}
>
{children}
</GlobalContext.Provider>
);
};
export default AppContext;
Let's break it down into simple terms:
Creating a Context:
import React, { createContext, useContext, ReactNode, Dispatch, SetStateAction } from 'react'; export interface GlobalContextTypes { target: string; options: string[]; setTarget: Dispatch<SetStateAction<string>>; changeTarget: (name: string) => void; } const GlobalContext = createContext<GlobalContextTypes | undefined>(undefined);
I import necessary dependencies from React, including
createContext
anduseContext
.I define an interface
GlobalContextTypes
to describe the shape of the data I want to store in the context. It includestarget
(a string),options
(an array of strings),setTarget
(a function to settarget
), andchangeTarget
(a function to change thetarget
).I create a new context called
GlobalContext
with the specified data shape.
Creating a Custom Hook:
export const useGlobalContext = () => useContext(GlobalContext);
- I create a custom hook
useGlobalContext
to easily access the data stored in myGlobalContext
. This hook can be used in other components to get the context's values.
- I create a custom hook
Creating a Provider Component:
interface AppContextProps { children: ReactNode; } const AppContext: React.FC<AppContextProps> = ({ children }) => { const [target, setTarget] = useState<string>("Home"); const options: string[] = ["Home", "Street"]; const changeTarget = (name: string) => { setTarget(name); }; return ( <GlobalContext.Provider value={{ target, options, setTarget, changeTarget, }} > {children} </GlobalContext.Provider> ); }; export default AppContext;
I define a component
AppContext
that serves as the provider for my context. It takes achildren
prop, which represents the content that will be wrapped by this provider.Inside
AppContext
, I set up the initial state fortarget
using theuseState
hook, initializing it with "Home." I also define anoptions
array and a functionchangeTarget
that allows me to update thetarget
.I wrap them
children
with theGlobalContext.Provider
, passing in the values I want to share with the context.
In summary, this code establishes a context called GlobalContext
that holds data related to a target and its options. The context can be accessed using the useGlobalContext
custom hook, and I've created a Provider
component (AppContext
) to set and provide the context's values to the components within its scope. This allows components in my application to share and update the target
and options
state using the Context API in TypeScript.
Import the Context API in main.tsx to use them in the entire project
Lets see inside main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import AppContext from "./context.tsx";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<AppContext>
<App />
</AppContext>
</React.StrictMode>
);
The code I provided is the entry point of a React application that integrates the Context API. Let's break down the relevant parts for beginners in simple terms:
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import AppContext from "./context.tsx";
Import Statements:
- I am importing necessary dependencies like
React
,ReactDOM
, myApp
component, CSS styles, andAppContext
.
- I am importing necessary dependencies like
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<AppContext>
<App />
</AppContext>
</React.StrictMode>
);
Rendering the Application:
<AppContext>
is where the Context API comes into play. I am wrapping my entire application with this component, and that means any component within the<AppContext>
will have access to the data provided by the context.<App />
is my main application component, and it's nested within the<AppContext>
. This means that theApp
component and any of its child components can access and use the data provided by theAppContext
.
In simple terms, what I've done in this code is:
Set up React application to render within an HTML element with the id "root."
Wrapped my entire application with
<AppContext>
, which means I am providing a shared context to all components within my app.Rendered the
App
component within the context, allowing it and its child components to access and use the data defined in theAppContext
.
This enables me to manage and share data across different parts of my application using the Context API, making it accessible where needed while keeping my component tree organized and efficient.
Let's use the Context API in ChildComponent.tsx
Let's see how I used Context API in ChildComponent.tsx:
import {useGlobalContext} from '../context/MyContext.tsx'
const ChildComponent=()=>{
const context=useGlobalContext();
if(!context)
{
return null;
}
const {target,options,changeTarget,}=context;
return (
<div>
{options.map((e:string)=>{
return(
<button onCLick={()=>changeTarget=(e)}>{e}</button>
)
}
<div>Selected:{target}</div>
</div>
);
}
export default ChildComponent;
Let's break down the relevant parts of Context API in simple terms:
import { useGlobalContext } from '../context/MyContext.tsx'
Import Statement:
- I am importing the
useGlobalContext
hook from myMyContext.tsx
file. This hook allows me to access the context data that I've defined in my context.
- I am importing the
const ChildComponent = () => {
const context = useGlobalContext();
if (!context) {
return null;
}
const { target, options, changeTarget } = context;
Using the Context:
Inside the
ChildComponent
function, I call theuseGlobalContext
hook to access the context data defined inMyContext.tsx
. This hook essentially connects me component to the context, providing access to the data stored in the context.I check if the
context
exists. If it doesn't, it means that the context might not be available (e.g., if the context hasn't been set up properly or if it's outside the scope of the provider). In that case, I will returnnull
to avoid rendering anything, preventing potential errors.
return (
<div>
{options.map((e: string) => {
return (
<button onClick={() => changeTarget(e)}>{e}</button>
)
})}
<div>Selected: {target}</div>
</div>
);
Rendering Components with Context Data:
I am rendering the component's user interface based on the context data I've accessed.
I use a
map
function to iterate over theoptions
array from the context. For each option, I create a button. When the button is clicked, it calls thechangeTarget
function from the context with thee
(which is the current option). This allows me to change thetarget
value in the context when a button is clicked.Finally, I display the currently selected target by accessing the
target
value from the context.
In simple terms, what's happening in this ChildComponent
is:
It uses the
useGlobalContext
hook to access the context data defined inMyContext.tsx
.It checks if the context data is available, and if it is, it renders a list of buttons based on the
options
from the context.When a button is clicked, it calls the
changeTarget
function from the context to update thetarget
value.It displays the currently selected target, which is part of the context data.
This is how the Context API allows me to share and manage data across different components in my application. The ChildComponent
can interact with and display data from the context without needing to pass it through props, making m code more organized and efficient.
Conclusion
In this article, we've explored the Context API in React with TypeScript, specifically in the context of a Vite project. The Context API provides a powerful way to manage and share state across your components, eliminating the need to pass data through props at each level of your component tree. This approach simplifies data management and promotes a cleaner and more efficient code structure.
We've walked through the essential components of a Context API implementation, from setting up the file structure to defining the context and creating a provider component. With a basic understanding of how the Context API works, you can create a shared global state for your application and access it wherever needed.
In the example provided, we've seen how a child component, ChildComponent
, effortlessly accesses and modifies the context's data, making your application more organized and scalable. This approach simplifies data sharing and management, especially in larger and more complex projects.
As you continue to explore React and build applications, the Context API, combined with TypeScript and Vite, becomes a valuable tool for keeping your codebase clean and maintainable. It allows you to efficiently share data and functionality between components, leading to a more robust and user-friendly user interface.
So, the next time you find yourself in a situation where you need to share data across multiple components, consider giving the Context API a try. It might just be the solution you need to streamline your application's state management and improve your development workflow. Happy coding!