Reader small image

You're reading from  Learn React with TypeScript - Second Edition

Product typeBook
Published inMar 2023
Reading LevelBeginner
PublisherPackt
ISBN-139781804614204
Edition2nd Edition
Languages
Tools
Right arrow
Author (1)
Carl Rippon
Carl Rippon
author image
Carl Rippon

Carl Rippon has been in the software industry for over 20 years developing a complex lines of business applications in various sectors. He has spent the last 8 years building single-page applications using a wide range of JavaScript technologies including Angular, ReactJS, and TypeScript. Carl has also written over 100 blog posts on various technologies.
Read more about Carl Rippon

Right arrow

State Management

In this chapter, we’ll learn about shared state, which is state that is used by several different components. We will explore three approaches to managing shared state, discussing the pros and cons of each approach.

To do this, we will build a simple app containing a header that displays the user’s name, with the main content also referencing the user’s name. The user’s name will be stored in state that needs to be accessed by several components.

We will start with the simplest state solution. This is to use one of React’s state hooks to store the state and pass it to other components using props. This approach is often referred to as prop drilling.

The second approach we will learn about is a feature in React called context. We will learn how to create a context containing a state and let other components access it.

The last approach we will cover is a popular library called Redux. We will take the time to understand...

Technical requirements

We will use the following technologies in this chapter:

All the code snippets in this chapter can be found online at https://github.com/PacktPublishing/Learn-React-with-TypeScript-2nd-Edition/tree/main/Chapter8.

Creating the project

We will develop our form using Visual Studio Code and a new Create React App-based project setup. We’ve previously covered this several times, so we will not cover the steps in this chapter – instead, see Chapter 3, Setting Up React and TypeScript.

We will style the form with Tailwind CSS. We also previously covered how to install and configure Tailwind in Create React App in Chapter 5, Approaches to Styling Frontends. So, after you have created the React and TypeScript project, install and configure Tailwind.

We will also use the @tailwindcss/forms plugin to style the form. So, install this plugin as well – see Chapter 7, Working with Forms, for information on how to do this.

The app we will build will contain a header and some content beneath it. Here is the component structure we will create:

Figure 8.1 – App component structure

Figure 8.1 – App component structure

The header will have a Sign in button to authenticate and authorize...

Using prop drilling

In this first state management approach, we will store the user, permissions, and loading state in the App component. The App component will then pass this state to the Header and Main components using props.

So, this approach uses React features that we are already aware of. The approach is referred to as prop drilling because the state is passed down the component tree using props.

Carry out the following steps to rework the App component to store the user, permissions, and loading state, and pass this state down to the Header and Main components:

  1. Open App.tsx and start by removing all the existing code and adding the following import statements:
    import { useReducer } from 'react';
    import { Header } from './Header';
    import { Main } from './Main';
    import { authenticate, User } from './api/authenticate';
    import { authorize } from './api/authorize';

We have imported useReducer from React to store the...

Using React context

In this section, we will learn a feature in React called context. We will then refactor the app from the last section to use React context.

Understanding React context

React context is an object that can be accessed by components. This object can contain state values, so it provides a mechanism for sharing state across components.

A context is created using a createContext function as follows:

const SomeContext = createContext<ContextType>(defaultValue);

A default value for the context must be passed into createContext. It also has a generic type parameter for the type that represents the object created by createContext.

The context also contains a Provider component that needs to be placed above components requiring access to the context object in the component tree. A provider wrapper component can be created that stores the shared state and passes it to the context Provider component as follows:

export function SomeProvider({ children...

Using Redux

In this section, we will learn about Redux before using it to refactor the app we have been working on to use it.

Understanding Redux

Redux is a mature state management library that was first released in 2015. It was released before React context and became a popular approach for shared state management.

Creating a store

In Redux, the state lives in a centralized immutable object referred to as a store. There is only a single store for the whole app. Like useReducer, the state in a store is updated by dispatching an action, which is an object containing the type of change and any data required to make the change. An action is handled by a reducer function, which creates a new version of the state.

In the past, a lot of code was needed to set up a Redux store and consume it in a React component. Today, a companion library called Redux Toolkit reduces the code required to use Redux. A Redux store can be created using the Redux Toolkit’s configureStore...

Summary

In this chapter, we built a small one-page app that contained components that needed to share state. We started by using our existing knowledge and used props to pass the state between the components. We learned that a problem with this approach was that components not needing access to the state are forced to access it if its child components do need access to it.

We moved on to learn about React context and refactored the app to use it. We learned that React context can store state using useState or useReducer. The state can then be provided to components in the tree using the context’s Provider component. Components then access the context state via the useContext hook. We found that this was a much nicer solution than passing the state via props, particularly when many components need access to the state.

Next, we learned about Redux, which is similar to React context. A difference is that there can only be a single Redux store containing the state, but there...

Questions

Answer the following questions to check what you have learned in this chapter:

  1. We have a context defined as follows to hold the theme state for an app:
    type Theme = {
      name: string;
      color: 'dark' | 'light';
    };
    type ThemeContextType = Theme & {
      changeTheme: (
        name: string,
        color: 'dark' | 'light'
      ) => void;
    };
    const ThemeContext = createContext<ThemeContextType>();

The code doesn’t compile though; what is the problem?

  1. The context from question 1 has a provider wrapper called ThemeProvider, which is added to the component tree as follows:
    <ThemeProvider>
      <Header />
      <Main />
    </ThemeProvider>
    <Footer />

The theme state is undefined when destructured from useContext in the Footer component. What is the problem?

  1. Is it possible to have two React contexts...

Answers

  1. createContext must be passed a default value when using it with TypeScript. Here’s the corrected code:
    const ThemeContext = createContext<ThemeContextType>({
      name: 'standard',
      color: 'light',
      changeTheme: (name: string, color: 'dark' | 'light') => {},
    });
  2. Footer must be placed inside ThemeProvider as follows:
    <ThemeProvider>
      <Header />
      <Main />
      <Footer />
    </ThemeProvider>
  3. Yes, there is no limit on the number of React contexts in an app.
  4. No, only a single Redux store can be added to an app.
  5. useDispatch can’t be used directly to dispatch an action – it returns a function that can be used to dispatch an action:
    const dispatch = useDispatch();
    function handleChangeTheme({ name, color }: Theme) {
      dispatch(changeThemeAction(name, color));
    }
  6. Yes, local state defined using useState or useReducer...
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Learn React with TypeScript - Second Edition
Published in: Mar 2023Publisher: PacktISBN-13: 9781804614204
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Carl Rippon

Carl Rippon has been in the software industry for over 20 years developing a complex lines of business applications in various sectors. He has spent the last 8 years building single-page applications using a wide range of JavaScript technologies including Angular, ReactJS, and TypeScript. Carl has also written over 100 blog posts on various technologies.
Read more about Carl Rippon