How to write React components in TypeScript (2022)
Tags: react, beginners, todayisearched, typescript
Published: 2022-11-23 19:38:05


## Introduction

React is a small library, yet it offers its users a lot of flexibility in how to use it. React is a library that allows users to create component-based applications, so naturally creating components is what will be the foundation of your application code. However, React offers multiple ways to define components, and is not very clear in which cases which method is preferred. This raises a lot of questions from both beginners and experienced React developers. Is there a best way to write a React component? In a codebase consistency is a property that is highly valued for the maintainability of your application.

## React component definitions

### React.createClass

The original way to create React components was through calling the function `React.createClass`. An object containing the lifecycle methods was passed to define the component. It is unlikely you will encounter components using this method in the current codebase since this method has been deprecated since React 15.5.0.

```javascript
// https://jsfiddle.net/vjeux/VkebS/
var Hello = React.createClass({
  render: function () {
    return React.DOM.div({}, "Hello " + this.props.name);
  },
});
Hello = React.createFactory(Hello);

React.render(Hello({ name: "World" }), document.body);
```

### ES6 Class-based components

React introduced ES6 class-based components in React [0.13](https://reactjs.org/blog/2015/02/24/react-v0.13-rc1.html#new-features). Class-based components are the most verbose way to define a React component. They are the most flexible in terms of the methods you can implement on the component. They offer the most control over the component lifecycle. Class-based components have dedicated methods that are triggered during the component lifecycle.

#### Deprecation

> Class components are still supported by React, but we don’t recommend using them in new code.

If you work on an existing code base, you might have seen them. If you are writing a new React application, it is not the [preferred way](https://reactjs.org/docs/hooks-faq.html#should-i-use-hooks-classes-or-a-mix-of-both) to write components. However, they remain fully supported and the recommendation from the React team is to not spend time on rewriting these components unless you already had plans to rewrite them for other reasons (such as bug fixes).

```typescript
class MyComponent extends React.Component<MyComponentProps> {
  render() {
    return <div>Hello World</div>;
  }
}
```

#### PureComponent

For performance reasons, you might not want your component to be re-rendered unless either state or props are changed. In this case, the `PureComponent` was used. Currently, better alternatives are available, but `PureComponent` remains available in React.

```typescript
class MyComponent extends React.PureComponent<MyComponentProps> {
  render() {
    return <div>Hello World</div>;
  }
}
```

### Stateless Function Components

Stateless function components were [introduced](https://reactjs.org/blog/2015/10/07/react-v0.14.html) in React 0.14. They are the most concise way to define a React component. Stateless Function components were introduced to being able to write components with a more simple syntax for components that do not have a state. Since they were introduced using arrow functions, it became a common practice to write these as such.

```typescript
const MyComponent: React.FC<MyComponentProps> = (props) => {
  return <div>Hello World</div>;
};
```

hen TypeScript support was added, the `React.SFC<T>` type was introduced, later renamed to `React.FC`. This type helps to define the return type, and a few optional properties as well as a generic type parameter for custom properties. In React 18, the `children` property is removed.

```typescript
interface FunctionComponent<P = {}> {
  (props: P, context?: any): ReactElement<any, any> | null;
  propTypes?: WeakValidationMap<P> | undefined;
  contextTypes?: ValidationMap<any> | undefined;
  defaultProps?: Partial<P> | undefined;
  displayName?: string | undefined;
}
```

### Function-based components

Using arrow functions was a concise way to define components, however, it came with a few downsides as discussed in this [pull request](https://github.com/facebook/create-react-app/pull/8177).

- Provides an implicit definition of `children`. This is solved in React 18.
- Doesn't support generics.
- Makes "component as namespace pattern" more awkward.

The more simple function definition using a simple type for its properties resolves these issues. This style of writing components is also used in the new React documentation as well as the preferred style in the [Airbnb JavaScript Style guide](https://github.com/airbnb/javascript/tree/master/react#class-vs-reactcreateclass-vs-stateless).

```typescript
type MyComponentProps<T> = {
  genericProp: T;
};

function MyComponent<T>(props: MyComponentProps<T>) {
  return <div>Hello World</div>;
}

function SubComponent() {
  return <p>...</p>;
}

MyComponent.SubComponent = SubComponent;
```

## Conclusion

Historically, there have been several best ways to write React components. You likely have an existing codebase that uses a mixture of different ways to define components. It will be hard to move the legacy class-based components to function components, however, it might be feasible to go for the function declaration style for stateless components.

For new components, it does make sense to follow the style defined in the React documentation by writing components using a `function` definition. However, arrow functions using `React.FC` also remain a popular choice and are used by [Vercel](https://github.com/vercel/commerce/blob/main/site/components/auth/SignUpView.tsx) and the official [TypeScript](https://github.com/microsoft/TypeScript-Website/blob/v2/packages/typescriptlang-org/src/templates/pages/index.tsx) website

### Further reading

- [Kent C. Dodd](https://kentcdodds.com/blog/how-to-write-a-react-component-in-typescript)
- [Learn React](https://beta.reactjs.org/learn)