State Management in React with TypeScript

Overview

React applications require state management, and TypeScript adds another layer of type safety to them. We'll examine React's state management options, including its Context API and popular state management libraries while focusing on the use of TypeScript to ensure type-safe development.

Suppose you are new to React TypeScript or in your early days. I have published an article on “How to Get Started with React TypeScript”, which I highly recommend you read if you are experiencing difficulties or are still in your early days of understanding React TypeScript.

React Context API with TypeScript


Creating Context

 Through the React Context API, we can manage the state globally and pass it down the component tree.

// Context creation with TypeScript
//Compent File name is AuthContextProvider.tsx
import { createContext, useContext, ReactNode } from 'react';

interface AppState {
  user: string;
  isAuthenticated: boolean;
  setUser: (user: string) => void;
  setAuthentication: (isAuthenticated: boolean) => void;
}

const AppContext = createContext<AppState | undefined>(undefined);

interface AppProviderProps {
  children: ReactNode;
}

const AppProvider: React.FC<AppProviderProps> = ({ children }) => {
  const [user, setUser] = useState<string>('');
  const [isAuthenticated, setAuthentication] = useState<boolean>(false);

  const contextValue: AppState = {
    user,
    isAuthenticated,
    setUser,
    setAuthentication,
  };

  return <AppContext.Provider value={contextValue}>{children}</AppContext.Provider>;
};

export const useAppContext = () => {
  const context = useContext(AppContext);
  if (!context) {
    throw new Error('useAppContext must be used within an AppProvider');
  }
  return context;
};

Using Context in Components

By using context in components, you can pass data through the component tree without having to manually pass props at each level. This example shows how to use context with TypeScript.

// Using context in TypeScript components
//Compent File name is UserContextInfo.tsx
import React from 'react';
import { useAppContext } from './AuthContextProvider';

const UserInfo: React.FC = () => {
  const { user, isAuthenticated } = useAppContext();

  return (
    <div>
      <p>{`User: ${user}`}</p>
      <p>{`Authenticated: ${isAuthenticated}`}</p>
    </div>
  );
};

State Management Libraries with TypeScript


Redux with TypeScript

Redux is already capable of powerful state management, but TypeScript adds type safety as well.

//Using Redux with TypeScript as an example
// Install required packages: npm install redux react-redux @types/react-redux
//Compent File Name is: UserReduxInfo.tsx

import { createStore, Action } from 'redux';
import { Provider, useSelector, useDispatch } from 'react-redux';

interface RootState {
  user: string;
  isAuthenticated: boolean;
}

// Define Actions
interface SetUserAction extends Action<'SET_USER'> {
  payload: string;
}

interface SetAuthenticationAction extends Action<'SET_AUTHENTICATION'> {
  payload: boolean;
}

type AppAction = SetUserAction | SetAuthenticationAction;

//Reducer definition
const rootReducer = (state: RootState, action: AppAction): RootState => {
  switch (action.type) {
    case 'SET_USER':
      return { ...state, user: action.payload };
    case 'SET_AUTHENTICATION':
      return { ...state, isAuthenticated: action.payload };
    default:
      return state;
  }
};

// Create Store
const store = createStore(rootReducer, {
  user: '',
  isAuthenticated: false,
});

// Use Redux in Component
const UserInfoRedux: React.FC = () => {
  const user = useSelector((state: RootState) => state.user);
  const isAuthenticated = useSelector((state: RootState) => state.isAuthenticated);
  const dispatch = useDispatch();

  const handleLogin = () => {
    dispatch({ type: 'SET_USER', payload: 'JohnDoe' });
    dispatch({ type: 'SET_AUTHENTICATION', payload: true });
  };

  return (
    <div>
      <p>{`User: ${user}`}</p>
      <p>{`Authenticated: ${isAuthenticated}`}</p>
      <button onClick={handleLogin}>Login</button>
    </div>
  );
};

// Wrap App with Redux Provider
const AppWithRedux: React.FC = () => {
  return (
    <Provider store={store}>
      <UserInfoRedux />
    </Provider>
  );
};

Summary

Managing your state in React with TypeScript adds an extra layer of reliability to your code. No matter whether your application uses the React Context API or state management libraries like Redux, you can use TypeScript to make sure its state is type-safe, reducing the likelihood of runtime errors. You should explore all of these options, experiment with different approaches, and decide which is best for your project.

If you found this article useful, please like it and follow me on LinkedIn: https://www.linkedin.com/in/ziggyrafiq/. You can also find the source code on my GitHub page:   https://github.com/ziggyrafiq/typescript-react-state-management. Recently, I published a book on Amazon, “Understanding C#12 Coding Standards, Best Practices, and Standards in the Industry: Developing Robust and Maintainable Code in Today's Development Environment.” I recommend you read it as it provides lots of code examples, industry standards, and best practices using C# 12.  


Capgemini
Capgemini is a global leader in consulting, technology services, and digital transformation.