React Context API with Typescript Example
Tags: react, typescript, redux, javascript
Published: 2020-12-30 23:23:58

A quick example of React Context API with Typescript that can be adapted for different use cases. This example is based on storing an array of todos (which are stored as strings), and providing a function to add a new todo. But this can be replaced with anything (and renamed to anything).

#### Types

I like to start with defining the type definitions. In this case we have the todos, which are stored as a string array, and a function that adds a new todo:

#### **`types.ts`**
```tsx
export type TodosContextState = {
  todos: string[];
  addTodo: (name: string) => void;
};
```

#### Context Provider

Next we use this type to create a provider component that stores the state that we want to make available to other components using context. 

#### **`TodosProvider.tsx`**
```tsx
import React, { createContext, useState, FC } from "react";
import { TodosContextState } from "./types";

const contextDefaultValues: TodosContextState = {
  todos: [],
  addTodo: () => {}
};

export const TodosContext = createContext<TodosContextState>(
  contextDefaultValues
);

const TodosProvider: FC = ({ children }) => {
  const [todos, setTodos] = useState<string[]>(contextDefaultValues.todos);

  const addTodo = (newTodo: string) => setTodos((todos) => [...todos, newTodo]);

  return (
    <TodosContext.Provider
      value={{
        todos,
        addTodo
      }}
    >
      {children}
    </TodosContext.Provider>
  );
};

export default TodosProvider;
```

We set the default values for our context with `contextDefaultValues`. For functions we can just set them as `() => {}` to make typescript happy before they are set when we create the provider.

#### TodosProvider Module

I like to make my React components modules, so here is the index.ts for the `TodosProvider` module.

#### **`index.ts`**
```tsx
export { TodosContext, default } from "./TodosContext";
```

#### Consuming Context

Here is an example of using the todos context. It is as simple as:
```typescript
const { todos } = useContext(TodosContext);
```

Using this in a component would look something like this:

#### **`Todos.tsx`**
```tsx
import React, { useContext } from "react";
import TodosProvider, { TodosContext } from "./TodosContext";

const Todos = () => {
  const { todos, addTodo } = useContext(TodosContext);

  return (
    <div>
      <div>
        {todos.map((todo, i) => (
          <div key={i}>{todo}</div>
        ))}
      </div>
      <button onClick={() => addTodo("new todo")}>add todo</button>
    </div>
  );
};

export default () => (
  <TodosProvider>
    <Todos />
  </TodosProvider>
);
```

NOTE: By wrapping the `Todos` component with the `TodosProvider` component

```tsx
export default () => (
  <TodosProvider>
    <Todos />
  </TodosProvider>
);
```

This context will not be available to any other components (except for child components). If you would like this context to be shared between multiple components move it up the component tree so it covers all components that need to use it. It can even wrap the whole application.

#### Full example

Here's the example in full on codesandbox:

{% codesandbox 93kke %}