React Context with TypeScript: Part 3 - Context with class components
Tags: react, typescript
Published: 2020-03-04 04:21:21

---
title: React Context with TypeScript: Part 3 - Context with class components
published: true
description: How to use TypeScript in a class component to consume React context in a strongly-typed manner
tags: react,typescript
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/e9o0s3wupeiuxn3wb5ai.jpg
canonical_url: https://www.carlrippon.com/react-context-with-typescript-p3/
---

This is another post in a series of posts on [React context](https://reactjs.org/docs/context.html) with TypeScript. In the [previous post](https://www.carlrippon.com/react-context-with-typescript-p2/), we created a complex context and consumed it in a function component.

- Part 1 - [Simple context with function components](https://www.carlrippon.com/react-context-with-typescript-p1/)
- Part 2 - [Complex context with function components](https://www.carlrippon.com/react-context-with-typescript-p2/)
- Part 3 - [Context with class components](https://www.carlrippon.com/react-context-with-typescript-p3/) (this post)
- Part 4 - Creating a context with no default and no undefined check (coming soon ...)

In this post, we will learn about using React context with class components.

## Trying to use the context hook in a class component

We are going to continue using the context we created in the last post that allows consumers to share and set a theme. Let's update the `Header` component to be a class component:

```jsx
class Header extends React.Component {
  render() {
    const { theme, setTheme } = useTheme()!;

    return (
      <div style={{ backgroundColor: theme }}>
        <select
          value={theme}
          onChange={e => setTheme(e.currentTarget.value)}
        >
          <option value="white">White</option>
          <option value="lightblue">Blue</option>
          <option value="lightgreen">Green</option>
        </select>
        <span>Hello!</span>
      </div>
    );
  }
}
```

There is a problem with this implementation, though:

![Context hooks error](https://dev-to-uploads.s3.amazonaws.com/i/36nm42jejb6w9td2ek0w.png)

Hooks can only be called inside function components, so, the above code will error on the following line:

```typescript
const { theme, setTheme } = useTheme()!;
```

## Using the `context` property

React class components have a `context` property that we can use to consume a context. First, we need to tell the class what context it should use with a `static` `contextType` property, and then we can access the `context` property:

```jsx
class Header extends React.Component {
  static contextType = ThemeContext;

  render() {
    const { theme, setTheme } = this.context!;

    return (
      ...
    );
  }
}
```

Notice that we put an exclamation mark(`!`) after the `context` property to tell the TypeScript compiler that it isn't `undefined`.

Let's see what types `theme` and `setTheme` been inferred as:

![Context inferred type in class](https://dev-to-uploads.s3.amazonaws.com/i/bbvcvo5z04sgst4vt0ic.png)

Both `theme` and `setTheme` has been inferred to have the `any` type.

## Explicitly setting the type for the `context` property

At the moment, the consumed context isn't strongly-typed. We can explicitly define the classes `context` property with a type annotation to make it strongly-typed:

```jsx
class Header extends React.Component {
  static contextType = ThemeContext;
  context: React.ContextType<typeof ThemeContext>;

  render() {
    const { theme, setTheme } = this.context!;

    return (
      ...
    );
  }
}
```

Notice that we don't use `React.ContextType<ThemeContextType>` as the type annotation for the `context` property because we get a type error if we do so.

A full working implementation is available by clicking the link below. Give it a try and change the theme value and see the background change color.

[Open full implementation](https://codesandbox.io/s/react-ts-complex-context-class-mz473?fontsize=14&hidenavigation=1&theme=dark)

## Using the `Consumer` component

There is an alternative approach to consuming a context in a class component if we just need access to it in the JSX. This method is to use the contexts `Consumer` component:

```jsx
class Header extends React.Component {
  render() {
    return (
      <ThemeContext.Consumer>
        {value => (
          <div style={{ backgroundColor: value!.theme }}>
            <select
              value={value!.theme}
              onChange={e => value!.setTheme(e.currentTarget.value)}
            >
              <option value="white">White</option>
              <option value="lightblue">Blue</option>
              <option value="lightgreen">Green</option>
            </select>
            <span>Hello!</span>
          </div>
        )}
      </ThemeContext.Consumer>
    );
  }
}
```

The child of the `Consumer` component is a function that has the value of the context passed into it and returns the JSX we want to render. Notice that we have put an exclamation mark (`!`) after we reference `value` to tell the TypeScript compiler that this isn't `undefined`.

The benefit of this approach is that the `contextType` static property doesn't need to be implemented. We don't need to declare the `context` property with its type annotation as well.

Let's check the inferred type of the `value` parameter in the `Consumer` components child function:

![Consumer value inferred type](https://dev-to-uploads.s3.amazonaws.com/i/fd25s5nf4af17m3o7ut0.png)

The type of the `value` parameter is `ThemeContextType | undefined`

## Wrap up

We can use Reacts context in class components, but we can't use the `useContext` hook.

Using the `Consumer` component is a neat way of getting access to the context in the `render` method, which has its type inferred correctly.

The `context` property can be used in other lifecycle methods to get access to the context. We need to explicitly define a type annotation for the `context` property and specify the specific context in a `contextType` static property.

In the next post, we'll learn about an approach to creating a context without having to pass a default and then do any `undefined` checks when consuming it.

Originally published at [https://www.carlrippon.com/react-context-with-typescript-p3/](https://www.carlrippon.com/react-context-with-typescript-p3/) on Mar 03, 2020.