Check your Props!

Solomon Hawk, Senior Developer

Article Category: #Code

Posted on

I recently attended the inaugural React Week workshop in Provo, Utah (organized by Tyler McGinnis and sponsored by DevMountain) to learn about React, React-Router, and Firebase from the delightful Ryan Florence. One of the interesting topics that Ryan touched on is React's prop validation, which he insisted is one of the most important features of the library. This isn't surprising since JavaScript lacks a strong type system, which can lead to some interesting and hard to track down bugs.

React's PropTypes let you enforce that the incoming props for a component match what it's expecting to receive, which can help mitigate issues like trying to call array methods on non-arrays or attempting to use a value that turns out to be null. React gives you some helpful methods for doing these checks but they only protect you if you declare PropTypes for all the props your component uses. What if you or another developer working with one of your components sets a prop that doesn't have a PropType? React's prop validation can't help you there.

So I whipped up a little mixin to warn developers who make this mistake.

View the Mixin (gist)

Using the lifecycle methods for componentWillMount and componentWillReceiveProps, I can compare the props that are set on my component with the PropTypes declared within and I'll receive a warning if I set one that doesn't have a PropType rule associated with it. 

For example: given the following ListContainer component...

let ListContainer = React.createClass({
  // include the mixin</code><code>
  mixins: [ PropCheckMixin ], 
  // declare PropTypes
  propTypes: {
    list: React.PropTypes.array.isRequired,
    button: React.PropTypes.instanceOf(Button)
  },
  ...
})

Were I to include this component like so:

<ListContainer foo="bar" list={ .. } />

... I would see a warning in the console:

If you're using envify, you can turn this behavior off in production by exporting an empty object from the mixin instead.

module.exports = process.env.NODE_ENV === 'production' ? {} : {
  ...actual mixin...
}

Here's the mixin (from the gist at the top of this post), ES6 flavored:

let PropCheckMixin = {
  componentWillMount() {
    this.validateProps(this.props)
  },
  componentWillReceiveProps(nextProps) {
    this.validateProps(nextProps)
  },
  validateProps(props) {
    let { displayName, propTypes } = this.constructor
    for (let prop in props) {
      if (!propTypes[prop]) {
        console.warn(`You set a property "${prop}" on Component "${displayName}" but did not provide a PropType declaration for this prop.`)
      }
    }
  }
}
module.exports = PropCheckMixin

What do you think? How are you guarding against these types of bugs in your React code? Let us know!

Solomon Hawk

Solomon is a developer in our Durham, NC, office. He focuses on JavaScript development for clients such as ID.me. He loves distilling complex challenges into simple, elegant solutions.

More articles by Solomon

Related Articles