In this tutorial, you will learn about React prop-types and how you can use them to prevent bugs within your code. Any application written using React.js will be made up of many components. Unless you have a very boring website, you will want those components to render differently based on different states and interactions. One way of changing state within a component is to pass parameters into the component. In the React this is known as passing 'props'.

If you have a small website you may never need to think too hard about how you pass props around within your application. As your application grows and the number of components increases there comes a tipping point where it's impossible to remember the props required for each and every component, what props are essential for the component to work as expected, which ones are optional and even what datatype should each prop should be.

Let's say you have a prop called, displayText. It would be very easy to forget if displayText was a boolean used to render something. displayText could also be a prop used to display some text. When you have hundreds of props you need a way of documenting your props. Prop-types are one approach you can use with React to make passing props into components easier. If you are new to prop-types and would like to learn how to improve your code, then read on.

Install Prop-types

Prop-types used to come as part of the core react framework. As of React 15.5.0 prop-types was removed into its own package, prop-types. The reason for this is that prop-types are not the only way to do prop validation, TypeScript is another good option.

The way Prop-types work, is that when a component is loaded, React checks the prop-types definition against the props being passed into the component. If the framework finds a missing prop, or, an invalid value is passed for a prop, a warning is displayed when the code is being compiled. Another useful thing to know is that propTypes are only validated when your application is set within development mode, as it adds latency into your application's performance.

To install prop-types you can use this command:

npm install prop-types

An example of a basic prop-type definition is:

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';

class Footer extends PureComponent {
    render() {
        const { messages } = this.props;

        return (
            <div>
                {message.FooterText}
            </div>
        );
    }
}

Footer.propTypes = {
    messages: PropTypes.string.isRequired
};

export default Footer;

The code above should hopefully be fairly straight-forward to understand. At the bottom of the component, we set an object against the component propTypes property. The object will define the prop-type definition. This object will contain all the props the component expects and the type for each prop. The isRequired function can be thought of as a guard pattern. When you set isRequired you tell the framework that this prop needs to exist when the component is loaded, otherwise, it should throw an error. A more complex example of how a propType definition could look is shown below:

static propTypes = {
    loading: PropTypes.bool.isRequired,
    loadingMessage: PropTypes.string,
    products: PropTypes.array.isRequired,
    fetchProducts: PropTypes.func.isRequired,
    messages: PropTypes.shape({
        pageName: PropTypes.func.isRequired
    })
}

In the definition above, we define props of boolean, string, array, function() and shape(). The full list of available types you can validate against can be found in the documentation here. The shape prop-type is a really useful one to know about as it can help you write better code.

Anti-Patterns To Use With React-Props

When you start adding prop-type definition into all your components it is very easy to fall into hidden traps. Due to the hierarchical nature of React, it is common that you will need to pass down similar props related props into multiple places. A common approach people new to prop-type take is to define the prop definition from scratch in each component. This is an anti-pattern that leads to lots of duplication. One way to remove this overhead is to centralize your PropTypes using the shape function and then export those definitions so they can be used in a different place, for example, let's say you need to pass an address around:

import { shape, number, string, oneOf } from 'prop-types';

export const addressType = shape({
    street: string.isRequired,
    city: string.isRequired,
    postCode: string.isRequired,
});

To use the address definition within a component, you can import it like so:

import React, { Component } from 'react';
import { addressType } from '.types';

export default class Footer extends Component {
  static propTypes = {
    address: addressType.isRequired,
  };

Creating custom shapes can dramatically help reduce the amount of code you have to write. Remember that when we work with React you should always strive to pass the minimum props down through your components as this will make maintenance a lot easier later on.