React context provider typescript

React Context Api using TypeScript

tndungu / React-Context-Api-Project

An application that uses Context Api to manage global state of logged in user

React Context Api Project

An app with 3 components, Login, Home and Settings, that demonstrates managing of Global state using React Context. LoggedIn flag for the user is provided from a Context Provider and other components subscribe to context changes to know whether a user is logged in or not. The app is created using React and TypeScript.

Local Setup

  1. Clone the Repository using the following command: git clone https://github.com/tndungu/React-Context-Api-Project.git
  2. Open the Repository using your favorite text editor. I use Visual Studio Code as a personal preference.
  3. Open terminal and run the following: npm install
  4. Run the project using npm start. This will open the project in http://localhost:3000

Video

There is a step by step guide on building the project on YouTube.

React TypeScript Student App

Prerequisites

This tutorial assumes you have some basic knowledge of using TypeScript with React. You may go through TypeScript with React Tutorial to get started.

App Development: Step by Step Guide

To start a new typescript app, use the following command

yarn create-react-app context-typescript-app --template typescript 
npx create-react-app context-typescript-app --template typescript 

cd into student-app and yarn start OR npm start if using npm.

Читайте также:  What does java programming do

In the src folder, we will create a folder called components . Inside the folder lets create 3 simple components Login , Home and Settings . They will look as follows:

//Login.tsx export const Login = () =>  return ( <> div className="pageLayout"> div> h3>Login/h3> /div> div> button>Login/button> /div> /div> /> ); >; 
//Home.tsx export const Home = () =>  return ( div className='pageLayout'> div> h3>Home Page/h3> /div> div> /div> /div> ) > 
//Settings export const Settings = () =>  return ( div className='pageLayout'> div> h3>Settings/h3> /div> div> /div> /div> ) > 

Import the components in the App.tsx file.

import './App.css'; import  Home > from './components/Home'; import  Login > from './components/Login'; import  Settings > from './components/Settings'; function App()  return ( <> Login /> Home /> Settings /> /> ); > export default App; 

Add the following Styles to the App.css file.

.App  display: flex; width: 100%; align-items: center; justify-content: center; flex-direction: column; > .pageLayout display: flex; align-items: center; justify-content:space-between; border: 0.1rem solid tomato; border-radius: 0.3rem; width: 50%; height: 100px; margin: 10px; > button width: 100px; height: 25px; background-color: aqua; border-radius: 5px; cursor: pointer; > div margin: 10px; min-width: 100px; > .title max-width: 100px; > 

Image description

At this point, if you save all the files and run the app it should look like the below.

Create Context

In the App.tsx , we will create a context that will hold the state loggedIn which will be true if a user is logged in and false if a user is not logged in.

import './App.css'; import  Home > from './components/Home'; import  Login > from './components/Login'; import  Settings > from './components/Settings'; import  createContext, useState > from 'react' export const LoginContext = createContext( loggedIn: false, setLoggedIn: (loggedIn: false) =>  > >) function App()  const [loggedIn, setLoggedIn] = useStateboolean>(false) return ( LoginContext.Provider value= <loggedIn, setLoggedIn >>> Login /> Home /> Settings /> /LoginContext.Provider> ); > export default App; 

In the code above, LoginContext will have an object with 2 properties loggedIn which is a boolean value and setLoggedIn which is a function hook that is used to set the loggedIn value.
The LoginContext object comes with Provider React Component that allows consuming components to subscribe to context changes. We will pass a value prop to LoginContext.Provider . This value will be propagated down the component tree to every component that subscribes to context changes.

useContext

We have created the context now it’s time to consume it. In the components folder, let’s add the simple component DisplayLogin.tsx which looks as follows. In addition, let’s make the following changes to Login.tsx .

//DisplayLogin export const DisplayLogin = () =>  return ( div>h3>User is Logged in/h3>div> ) > 
//Login.tsx import  useContext > from 'react' import  LoginContext > from '../App' import  DisplayLogin > from './DisplayLogin'; export const Login = () =>  const  loggedIn, setLoggedIn > = useContext(LoginContext) return ( <> div className="pageLayout"> div> h3>Login/h3> /div>& DisplayLogin /> > div> button onClick= => setLoggedIn(!loggedIn)>>Login/button> /div> /div> /> ); >; 

Image description

From the Login.tsx component above, we have used the useContext hook to subscribe and consume the LoginContext. This enables us to get the global variable within Login.tsx without passing props. If you run the app, it should display as follows. Once you click the button, the message ‘User is Logged in’ is displayed.

Lets subscribe in the Home and Settings components as well. The 2 components will now look as follows:

//Home.tsx import  useContext > from 'react' import  LoginContext > from '../App' import  DisplayLogin > from './DisplayLogin'; export const Home = () =>  const  loggedIn, setLoggedIn > = useContext(LoginContext) return ( div className='pageLayout'> div> h3>Home Page/h3> /div> !loggedIn && DisplayLogin /> > div> /div> /div> ) > 
//Settings import  useContext > from 'react' import  LoginContext > from '../App' import  DisplayLogin > from './DisplayLogin'; export const Settings = () =>  const  loggedIn, setLoggedIn > = useContext(LoginContext) return ( div className='pageLayout'> div> h3>Settings/h3> /div> !loggedIn && DisplayLogin /> > div> /div> /div> ) > 

At this point, if you click the Login button, the message ‘User is Logged in’ is displayed on all components. This is because we have subscribed to the context of all the 3 components.

Image description

Refactoring Context

The useContext() has been used in all components. This is not best practice since it means we’re exposing the whole context in every component whereas it might not be necessary to do so. In addition, there are duplications in our code. So we need to move our Context code to its file. We can also create a custom hook to wrap LoginContext.Provider . The final code will look as follows:

//App.tsx import './App.css'; import  Home > from './components/Home'; import  Login > from './components/Login'; import  Settings > from './components/Settings'; import  LoginProvider > from './Context/LoginContext' function App()  return ( LoginProvider> Login /> Home /> Settings /> /LoginProvider> ); > export default App; 
// Context/LoginContext import React,  useState, createContext > from "react"; interface LoginProviderProps children: React.ReactNode > export const LoginContext = createContext(loggedIn: false,setLoggedIn: (loggedIn: boolean) => <>>); export const LoginProvider = ( children >: LoginProviderProps) =>  const [loggedIn, setLoggedIn] = useState(false); return ( LoginContext.Provider value= <loggedIn,setLoggedIn >>> children> /LoginContext.Provider> ); >; 
//useLoginContext import useContext> from 'react' import  LoginContext > from '../Context/LoginContext' export const useLoginContext = () =>  return useContext(LoginContext) > 
//Home.tsx import  useLoginContext > from './useLoginContext' export const Home = () =>  const  loggedIn > = useLoginContext() return ( div className='pageLayout'> div> h3>Home Page/h3> /div> loggedIn && div>h3>User is Logged in/h3>div> > div> /div> /div> ) > 
//Login.tsx import  useLoginContext > from "./useLoginContext"; export const Login = () =>  const  loggedIn, setLoggedIn > = useLoginContext() return ( <> div className="pageLayout"> div> h3>Login/h3> /div> loggedIn && div>h3>User is Logged in/h3>div> > div> button onClick= => setLoggedIn(!loggedIn)>>loggedIn ? 'Logout' : 'Login'>/button> /div> /div> /> ); >; 
//Settings import  useLoginContext > from './useLoginContext' export const Settings = () =>  const loggedIn > = useLoginContext() return ( div className='pageLayout'> div> h3>Settings/h3> /div> loggedIn && div>h3>User is Logged in/h3>div> > div> /div> /div> ) > 

Conclusion

Congratulations! You have gone through all that is required to create and use Context in React using TypeScript. Context API is a popular way of managing the global state for small to medium-level applications. For large-scale applications, REDUX might be a better way of managing the state.
Feel free to comment below in case you need further assistance.

Источник

TypeScript and React: Context

Stefan Baumgartner

React’s context API allows you to share data on a global level. To use it, you need two things:

  • A provider. Providers pass data to a subtree.
  • Consumers. Consumers are components that consume the passed data inside render props

With React’s typings, context works without you doing anything else. Everything is done using type inference and generics. You consume all the implied type information which @types/react produces for you.

Create a context #

Let’s have a look! First, we create a context. The most important thing is to not forget default properties.

import React from 'react';

export const AppContext = React.createContext(
authenticated: true,
lang: 'en',
theme: 'dark'
>);

And with that, everything you need to do in terms of types is done for you. We have three properties called authenticated , lang and theme , they are of types boolean and string respectively. React’s typings take this information to provide you with the correct types when you use them.

Provide context #

Our app component provides this context. It also sets values different from default values.

const App = () =>  
return AppContext.Provider value=
lang: 'de',
authenticated: true,
theme: 'light'
> >>
Header/>
/AppContext.Provider>
>

Now, every component inside this tree can consume this context. You already get type errors when you forget a property or use the wrong type:


const App = () =>
// ⚡️ compile error! Missing properties
return AppContext.Provider value=
lang: 'de',
> >>
Header/>
/AppContext.Provider>
>

Now, let’s consume our global state.

Consume context #

Consuming context is done via render props (see the previous chapter) for more details). You can destructure you render props as deep as you like, to get only the props you want to deal with:

const Header = () =>  
return AppContext.Consumer>

(authenticated>) =>
if(authenticated)
return h1>Logged in!/h1>
>
return h1>You need to sign in/h1>
>
>
/AppContext.Consumer>
>

Because we defined our properties earlier with the right types, authenticated is of type boolean at this point. Again we didn’t have to do anything to get this extra type safety.

Context without default values #

The whole example above works best if we have default properties and values. Sometimes, you don’t have default values or you need to be more flexible in which properties you want to set.

Generics for createContext and the Partial helper can help you greatly with that:

import React from 'react';

// We define our type for the context properties right here
type ContextProps =
authenticated: boolean,
lang: string,
theme: string
>;

// we initialise them without default values, to make that happen, we
// apply the Partial helper type.
export const AppContext =
React.createContextPartialContextProps>>(>);

const Header = () =>
return AppContext.Consumer>

(authenticated>) =>
if(authenticated)
return h1>Logged in!/h1>
>
return h1>You need to sign in/h1>
>
>
/AppContext.Consumer>
>

// Now, we can set only the properties we really need
const App = () =>
return AppContext.Provider value=
authenticated: true,
> >>
Header/>
/AppContext.Provider>
>

There’s a StackBlitz you can check out.

And that’s context! I think it’s nicer to use with the hooks API, but nevertheless, it’s incredibly useful!

Источник

Оцените статью