React Context with TypeScript: Part 1 - Simple context with function components
Tags: react, typescript
Published: 2020-02-19 04:06:55

---
title: React Context with TypeScript: Part 1 - Simple context with function components
published: true
description: How to use TypeScript to create a strongly-typed React context for function components where the context isn't changed by the consumer
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-p1/
---

[React context](https://reactjs.org/docs/context.html) allows several components in a tree to share some data. It's more convenient than passing the data via props down the component tree. How can we use TypeScript to create a strongly-typed context? Is it possible to do this for use with function components as well as class components? This is the first of four blog posts that go through this topic.

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

In this post, we will create a strongly-typed React context and consume it in a function component that doesn't doesn't change the context.

## Creating a context

A common use case for using context is to provide theme information to components in an app. We are going to provide a color value in a context that components can use.

Let's start by creating our theme using Reacts `createContext` function:

```jsx
const defaultTheme = "white";
const ThemeContext = React.createContext(
  defaultTheme
);
```

We are required to provide a default value for the context, which in our case is `"white"`.

The type of the context is inferred to be `React.Context<string>`:

![Inferred type for a simple context](https://dev-to-uploads.s3.amazonaws.com/i/el3gzb3xcsaogtn139i5.png)

Nice - exactly as we require!

## Creating a Context provider

Next, we are going to create the provider component:

```jsx
type Props = {
  children: React.ReactNode
};
export const ThemeProvider = ({
  children
}: Props) => {
  const [theme, setTheme] = React.useState(
    defaultTheme
  );

  React.useEffect(() => {
    // We'd get the theme from a web API / local storage in a real app
    // We've hardcoded the theme in our example
    const currentTheme = "lightblue";
    setTheme(currentTheme);
  }, []);

  return (
    <ThemeContext.Provider value={theme}>
      {children}
    </ThemeContext.Provider>
  );
};
```

We hold the theme value in the state. This means that when it changes, React will automatically re-render the provider's children with the new theme.

We get the current theme value using Reacts `useEffect` hook and update the `theme` state value.

Out theme provider component returns the `Provider` component within the context with our theme value. The provider is wrapped around all the children in the component tree.

## Creating a custom hook for consuming the context

We can create a custom hook that will allow function components to consume our context:

```jsx
export const useTheme = () =>
  React.useContext(ThemeContext);
```

Let's check what the return type of `useTheme` has been inferred as:

![Inferred type for context hook](https://dev-to-uploads.s3.amazonaws.com/i/uo04eoo7ek87iokikxt4.png)

The return type of `useTheme` is `string` because this is the type of the context value.

## Adding the provider to the component tree

The `ThemeProvider` component can now be placed in an appropriate position in the component tree.

```jsx
const App = () => (
  <ThemeProvider>
    <Header />
  </ThemeProvider>
);
```

Components below it will have access to the context, but components above it won't. So, the `Header` component will have access to the context.

## Consuming the context

The `Header` component can access the context by using the `useTheme` hook we created. This allows the header component to render an element that has its background color set to the theme color:

```jsx
const Header = () => {
  const theme = useTheme();
  return (
    <div style={{ backgroundColor: theme }}>
      Hello!
    </div>
  );
};
```

A working version of `ThemeContext` is available by clicking the link below. When the app is run, _Hello_ will appear with a light blue background.

[Open working version](https://codesandbox.io/s/react-ts-context-simple-3boq8?fontsize=14&hidenavigation=1&theme=dark)

## Wrap up

The type for the context is inferred correctly if a sensible default is provided when it is created. If the context is providing values that consumers don't change, then this is fine. However, what if we want the user to change the theme? In this case, our context would need to provide a function for updating the theme, and this can't be provided as a default value. In the next post, we will extend our theme context so that consumers can update the value.

*Originally published at [https://www.carlrippon.com/react-context-with-typescript-p1/](https://www.carlrippon.com/react-context-with-typescript-p1/) on Feb 18, 2020*.