Education
Developer Advocate
Last updated on Jul 19, 2024
Last updated on Jul 19, 2024
React's Context API is a powerful feature for effectively propagating data through component trees without manually passing props down at every level. In a TypeScript environment, React Context ensures type safety, providing developers a robust way to manage state across many components.
TypeScript, a superset of JavaScript, adds static types to the language. Combined with React Context, it allows for defining the shape of the context value, which can prevent type errors and enhance code quality and maintainability.
In this blog, we will explore creating and using React Context with TypeScript, ensuring that our context is correctly typed and our components receive the right data.
Before diving into the implementation, it's crucial to understand what context is and why it's beneficial in a React application. Context provides a way to share values, like user authentication, themes, or a preferred language, between components without explicitly passing a prop through every level of the tree.
In TypeScript, context is not just about passing data but also about ensuring that the data passed is of the correct type. This is where TypeScript shines, as it allows you to define the structure of the data you expect to be present in the context, thus avoiding potential runtime errors and making the developer experience much safer and more predictable.
To create a new context in React with TypeScript, you start by importing the necessary functions from React and defining the shape of the context using interfaces or types.
1import React from 'react'; 2 3interface UserContextType { 4 name: string; 5 age: number; 6 updateUser: (name: string, age: number) => void; 7} 8 9const UserContext = React.createContext<UserContextType | null>(null); 10
In the above example, we define an interface UserContextType that specifies the structure of our context value. We then use the React.createContext function to create a new context, passing the default value as null. The generic type UserContextType | null ensures that the context can either be of UserContextType or null, providing a way to handle the absence of a value.
Once the context is created, we need to define a provider component that will wrap the part of our component tree that needs access to the context value. The provider component holds the state and passes it down to the consuming components.
1const UserProvider: React.FC = ({ children }) => { 2 const [user, setUser] = React.useState<UserContextType>({ 3 name: 'John Doe', 4 age: 30, 5 updateUser: (name: string, age: number) => setUser({ name, age }), 6 }); 7 8 return ( 9 <UserContext.Provider value={user}> 10 {children} 11 </UserContext.Provider> 12 ); 13}; 14
In this code snippet, we create a UserProvider component that uses the useState hook to manage the user state. The updateUser function is a part of the state and is used to update the user's name and age. The UserContext.Provider component receives the user state as its value prop, making it available to any child components.
To access the context value within a component, React provides the useContext hook. In TypeScript, you can use this hook with the context object you've created to ensure that the consumed context is of the correct type.
1import React, { useContext } from 'react'; 2import { UserContext } from './UserContext'; 3 4const UserProfile: React.FC = () => { 5 const userContext = useContext(UserContext); 6 7 if (!userContext) { 8 throw new Error('UserProfile must be used within a UserProvider'); 9 } 10 11 return ( 12 <div> 13 <p>Name: {userContext.name}</p> 14 <p>Age: {userContext.age}</p> 15 <button onClick={() => userContext.updateUser('Jane Doe', 25)}>Update User</button> 16 </div> 17 ); 18}; 19
In the UserProfile component, we use the useContext hook with UserContext to access the context value. We also include a runtime check to ensure that userContext is not null, throwing an error if the component is used outside of a UserProvider. This pattern is a safeguard to ensure the context is used correctly within the component tree.
When using TypeScript with React Context, defining the types or interfaces for the context value is important to ensure type safety. This helps in catching potential bugs during development time rather than at runtime.
1interface ThemeContextType { 2 theme: string; 3 toggleTheme: () => void; 4} 5 6export const ThemeContext = React.createContext<ThemeContextType | null>(null); 7
Here, we define a ThemeContextType interface with a theme property and a toggleTheme method. The context is then created with the possibility of being null if no provider is found up the component tree.
React Context with TypeScript is particularly useful when you need to share data across different levels of components. It prevents prop drilling and makes your code cleaner and more maintainable.
1const App: React.FC = () => { 2 return ( 3 <UserProvider> 4 <UserProfile /> 5 {/* Other components that need access to UserContext */} 6 </UserProvider> 7 ); 8}; 9
In the App component, we wrap the UserProfile component with UserProvider. This makes the user context available to UserProfile and any other components nested within UserProvider.
Prop drilling is a common issue in React applications where you need to pass props through multiple levels of components that do not necessarily need the data. Context API, combined with TypeScript, offers a solution to this problem by allowing you to access the data at any level without passing it through every single level.
1// Inside a deeply nested component 2const DeeplyNestedComponent: React.FC = () => { 3 const userContext = useContext(UserContext); 4 // Now you can use userContext directly without prop drilling 5}; 6
Using the useContext hook, DeeplyNestedComponent can access the UserContext directly, eliminating the need to pass the user data down through props from parent to child components.
To illustrate the use of React Context with TypeScript, let's implement a simple theme context that allows components to access and toggle the current theme.
1import React, { useState } from 'react'; 2 3// Define the shape of the context data 4interface ThemeContextType { 5 currentTheme: string; 6 toggleTheme: () => void; 7} 8 9// Create the context with a default value 10export const ThemeContext = React.createContext<ThemeContextType>({ 11 currentTheme: 'light', 12 toggleTheme: () => {}, 13}); 14 15// Create a provider component 16export const ThemeProvider: React.FC = ({ children }) => { 17 const [theme, setTheme] = useState('light'); 18 19 const toggleTheme = () => { 20 setTheme(theme === 'light' ? 'dark' : 'light'); 21 }; 22 23 return ( 24 <ThemeContext.Provider value={{ currentTheme: theme, toggleTheme }}> 25 {children} 26 </ThemeContext.Provider> 27 ); 28}; 29
In this example, we define a ThemeContextType interface and create a ThemeContext with a default value. The ThemeProvider component manages the theme state and provides a toggleTheme function to switch between light and dark themes.
When using React Context with TypeScript, there are several best practices to follow:
By adhering to these best practices, you can leverage the full power of TypeScript to create more reliable and maintainable React applications.
While React Context with TypeScript is a powerful combination, there are some common pitfalls to be aware of:
By understanding these pitfalls and how to avoid them, you can create robust applications using React Context with TypeScript.
React Context API, when used with TypeScript, provides a scalable way to manage state across your application while ensuring type safety. By following the outlined steps and best practices, you can create a context that is easy to maintain and prevents common type-related bugs. Whether you're managing user data, application themes, or other global state, React Context with TypeScript is an invaluable tool in your development arsenal.
**Ready to take your React development skills to the next level? **
DhiWise the web and mobile app development platform streamlines application development by supporting popular technologies such as React, Next.js, HTML and so on. With it you can convert Figma design to code, cutomize UI and styling, and integrate API to app and more. Leverage the power of DhiWise and React Context with TypeScript effectively to build robust and maintainable applications. Sign up now!
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.