Mastering Props And PropTypes In React

Mastering Props And PropTypes In React

Do props and PropTypes confuse you? You’re not alone. I’m going to guide you through everything about props and PropTypes. They can make your life significantly easier when developing React apps. This tutorial will introduce you to the details about props, passing and accessing props, and passing information to any component using props.

Building React applications involves breaking down the UI into several components, which implies that we will need to pass data from one component to another. Props are an important mechanism for passing information between React components, and we’re going to look into them in great detail. This article would be incomplete without looking into PropTypes, because they ensure that components use the correct data type and pass the right data.

It’s always a good practice to validate the data we get as props by using PropTypes. You will also learn about integrating PropTypes in React, typechecking with PropTypes, and using defaultProps. At the end of this tutorial, you will understand how to use props and PropTypes effectively. It is important that you already have basic knowledge of how React works.

Understanding Props

React allows us to pass information to components using things called props (short for properties). Because React comprises several components, props make it possible to share the same data across the components that need them. It makes use of one-directional data flow (parent-to-child components). However, with a callback function, it’s possible to pass props back from a child to a parent component.

These data can come in different forms: numbers, strings, arrays, functions, objects, etc. We can pass props to any component, just as we can declare attributes in any HTML tag. Take a look at the code below:

<PostList posts={postsList} />

In this snippet, we are passing a prop named posts to a component named PostList. This prop has a value of {postsList}. Let’s break down how to access and pass data.

Passing and Accessing Props

To make this tutorial interesting, let’s create an application that shows a list of users’ names and posts. The app demo is shown below:

See the Pen Passing and Accessing Props by David Adeneye.

The app comprises collections of components: an App component, a PostList component, and a Post component.

The list of posts will require data such as the content and the name of the user. We can construct the data like so:

const postsList = [
  {
    id: 1,
    content: "The world will be out of the pandemic soon",
    user: "Lola Lilly",
  },
  {
    id: 2,
    content: "I'm really exited I'm getting married soon",
    user: "Rebecca Smith",
  },
  {
    id: 3,
    content: "What is your take on this pandemic",
    user: "John Doe",
  },
  {
    id: 4,
    content: "Is the world really coming to an end",
    user: "David Mark",
  },
];

After this, we need the App component to pull the data, Here is the basic structure of that component:

const App = () => {
  return (
    <div>
      <PostList posts={postsList} />
    </div>
  );
};

Here, we are passing an array of posts as a prop to the PostList (which we’ll create in a bit). The parent component, PostList, will access the data in postsList, which will be passed as posts props to the child component (Post). If you’ll remember, our app comprises three components, which we’ll create as we proceed.

Let’s create the PostList:

class PostList extends React.Component {
  render() {
    return (
      <React.Fragment>
        <h1>Latest Users Posts</h1>
        <ul>
          {this.props.posts.map((post) => {
            return (
              <li key={post.id}>
                <Post {...post} />
              </li>
            );
          })}
        </ul>
      </React.Fragment>
    );
  }
}

The PostList component will receive posts as its prop. It will then loop through the posts prop, this.props.posts, to return each posted item as a Post component (which we will model later). Also, note the use of the key in the snippet above. For those new to React, a key is a unique identifier assigned to each item in our list, enabling us to distinguish between items. In this case, the key is the id of each post. There’s no chance of two items having the same id, so it’s a good piece of data to use for this purpose.

Meanwhile, the remaining properties are passed as props to the Post component ( <Post {...post} /> ).

So, let’s create the Post component and make use of the props in it:

const Post = (props) => {
  return (
    <div>
      <h2>{props.content}</h2>
      <h4>username: {props.user}</h4>
    </div>
  );
};

We are constructing the Post component as a functional component, rather than defining it as a class component like we did for the PostList component. I did this to show you how to access props in a functional component, compared to how we access them in a class component with this.props. Because this a functional component, we can access the values using props.

We’ve learned now how to pass and access props, and also how to pass information from one component to the other. Let’s consider now how props work with functions.

Passing Functions Via Props

In the preceding section, we passed an array of data as props from one component to another. But what if we are working with functions instead? React allows us to pass functions between components. This comes in handy when we want to trigger a state change in a parent component from its child component. Props are supposed to be immutable; you should not attempt to change the value of a prop. You have to do that in the component that passes it down, which is the parent component.

Let’s create a simple demo app that listens to a click event and changes the state of the app. To change the state of the app in a different component, we have to pass down our function to the component whose state needs to change. In this way, we will have a function in our child component that is able to change state.

Sounds a bit complex? I have created a simple React application that changes state with the click of a button and renders a piece of welcome information:

See the Pen Passing Function via Props in React by David Adeneye.

In the demo above, we have two components. One is the App component, which is the parent component that contains the app’s state and the function to set the state. The ChildComponent will be the child in this scenario, and its task is to render the welcome information when the state changes.

Let’s break this down into code:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isShow: true,
    };
  }
  toggleShow = () => {
    this.setState((state) => ({ isShow: !state.isShow }));
  };
  render() {
    return (
      <div>
        <ChildComponent isShow={this.state.isShow} clickMe={this.toggleShow} />
      </div>
    );
  }
}

Notice that we’ve set our state to true, and the method to change the state is created in the App component. In the render() function, we pass the state of the app, as the prop isShow, to the ChildComponent component. We also pass the toggleShow() function as a prop named clickMe.

We will use this in the ChildComponent which looks like this:

class ChildComponent extends React.Component {
  clickMe = () => {
    this.props.clickMe();
  };
  render() {
    const greeting = "Welcome to React Props";
    return (
      <div style={{ textAlign: "center", marginTop: "8rem" }}>
        {this.props.isShow ? (
          <h1 style={{ color: "green", fontSize: "4rem" }}>{greeting}</h1>
        ) : null}
        <button onClick={this.clickMe}>
          <h3>click Me</h3>
        </button>
      </div>
    );
  }
}

The most important thing above is that the App component passes down a function as a prop to the ChildComponent. The function clickMe() is used for the click handler in the ChildComponent, whereas the ChildComponent doesn’t know the logic of the function — it only triggers the function when the button gets clicked. The state is changed when the function is called, and once the state has changed, the state is passed down as a prop again. All affected components, like the child in our case, will render again.

We have to pass the state of the app, isShow, as a prop to the ChildComponent, because without it, we cannot write the logic above to display greeting when the state is updated.

Now that we’ve looked at functions, let’s turn to validation. It’s always a good practice to validate the data we get through props by using PropTypes. Let’s dive into that now.

What Are PropTypes In React?

PropTypes are a mechanism to ensure that components use the correct data type and pass the right data, and that components use the right type of props, and that receiving components receive the right type of props.

We can think of it like a puppy being delivered to a pet store. The pet store doesn't want pigs, lions, frogs, or geckos — it wants puppies. PropTypes ensure that the correct data type (puppy) is delivered to the pet store, and not some other kind of animal.

In the section above, we saw how to pass information to any component using props. We passed props directly as an attribute to the component, and we also passed props from outside of the component and used them in that component. But we didn’t check what type of values we are getting in our component through props or that everything still works.

It’s totally upon us whether to validate the data we get in a component through props. But in a complex application, it is always a good practice to validate that data.

Using PropTypes

To make use of PropTypes, we have to add the package as a dependency to our application through npm or Yarn, by running the following code in the command line. For npm:

npm install --save prop-types

And for Yarn:

yarn add prop-types

To use PropTypes, we first need to import PropTypes from the prop-types package:

import PropTypes from 'prop-types';

Let’s use ProTypes in our app that lists users’ posts. Here is how we will use it for the Post component:

Post.proptypes = {
  id: PropTypes.number,
  content: PropTypes.string,
  user: PropTypes.string
}

Here, PropTypes.string and PropTypes.number are prop validators that can be used to make sure that the props received are of the right type. In the code above, we’re declaring id to be a number, while content and user are to be strings.

Also, PropTypes are useful in catching bugs. And we can enforce passing props by using isRequired:

Post.proptypes = {
  id: PropTypes.number.isRequired,
  content: PropTypes.string.isRequired,
  user: PropTypes.string.isRequired
}

PropTypes have a lot of validators. Here are some of the most common ones:

Component.proptypes = {
  stringProp: PropTypes.string,         // The prop should be a string
  numberProp: PropTypes.number,         // The prop should be a number
  anyProp: PropTypes.any,               // The prop can be of any data type
  booleanProp: PropTypes.bool,          // The prop should be a function
  functionProp: PropTypes.func          // The prop should be a function
  arrayProp: PropTypes.array            // The prop should be an array
}

More types are available, which you can check in React’s documentation].

Default Props

If we want to pass some default information to our components using props, React allows us to do so with something called defaultProps. In cases where PropTypes are optional (that is, they are not using isRequired), we can set defaultProps. Default props ensure that props have a value, in case nothing gets passed. Here is an example:

Class Profile extends React.Component{

  // Specifies the default values for props
  static defaultProps = {
    name: 'Stranger'
  };

  // Renders "Welcome, Stranger":
  render() {
    return <h2> Welcome, {this.props.name}<h2>
  }
}

Here, defaultProps will be used to ensure that this.props.name has a value, in case it is not specified by the parent component. If no name is passed to the class Profile, then it will have the default property Stranger to fall back on. This prevents any error when no prop is passed. I advise you always to use defaultProps for every optional PropType.

Conclusion

I hope you’ve enjoyed working through this tutorial. Hopefully, it has shown you how important props and propTypes are to building React applications, because without them, we wouldn’t be able to pass data between components when interactions happen. They are a core part of the component-driven and state-management architecture that React is designed around.

PropTypes are a bonus for ensuring that components use the correct data type and pass the right data, and that components use the right type of props, and that receiving components receive the right type of props.

If you have any questions, you can leave them in the comments section below, and I’ll be happy to answer every one and work through any issues with you.

References

  • “Thinking in React”, React Docs
  • “List and Keys”, React Docs
  • “Typechecking With PropTypes”, React Docs
  • “How to Pass Props to Components in React”, Robin Wieruch