React.js - Understanding Props and State for Component Composition

Another quick brain dump on my notes about React's props and state.

Understanding the different use cases for each allows for clear data management and a clean pattern when thinking about React component composition by creating Controller Views and 'dumb' Presentation Components.

Props and State

Data for React components are stored as props and state


React props

var UserForm = React.createClass({  
    getDefaultProps: function() {
        return {
            name: 'fullname',
            placeholder: 'Enter your name',
            value: ''
        };
    },
    render: function() {
        return (
            <CustomInput type="text"
               name={this.props.name}
               className="form-control"
               placeholder={this.props.placeholder}
               value={this.props.value}
               onChange={this.props.onChange}
            />
        );
    }
});
  • props (aka. properties) are references to parameters that are passed down from parent components.
  • The data is owned by the parent so prop data is immutable within the child component.
  • props facilitates uni-directional data-flow from parent to child components.
getDefaultProps
  • If the parent component doesn't declare value, you can set default props with getDefaultProps.
prop Validation

props can be validated through React.PropTypes, though it only runs in development environment of React. (By default, minified version of React runs in production mode.)

React.PropTypes allows setting explicit expectations about the expected data type for a component's props. It's a good way to debug, but since it only runs in dev environment, it's shouldn't be used in production to validate props.

Note: props that aren't required should have a default prop defined with getDefaultProps

Use React.PropTypes to Specify type: number, string, bool, etc.

React.PropTypes.array  
React.PropTypes.bool  
React.PropTypes.func  
React.PropTypes.number  
React.PropTypes.object  
React.PropTypes.string  

propTypes: Maps a validation function for each prop

propTypes: {  
    author: React.PropTypes.object.isRequired,
    onSave: React.PropTypes.func.isRequired,
    validate: React.PropTypes.func.isRequired,
    errors: React.PropTypes.object,
    hasErrors: React.PropTypes.func.isRequired
}

React state
var ManageAuthors = React.createClass({  
    getInitialState: function() {
        return {
            author: { id: '', firstName: '', lastName: '' }
        };
    },
    render: function() {
        return (
           <AuthorForm
            author={this.state.author}
            //onChange, run this.setAuthorState function
            onChange={this.setAuthorState}
            onSave={this.saveAuthor}
           />
        );
    }
});
  • state should be used in controller views (the top level component). This allows separating logic from Presentation Component markup.
  • state data is owned by the component so state is mutable data.
  • state is passed down to nested child components as immutable data via props.
getInitialState
  • Typically only used to set default state in the top level (controller view) component.

Component Composition - Controller Views

A Controller View is a convention to have a single, top level view that:

  • Owns state data
  • Interacts with any stores
  • Passes data down to children via props.

Setting up and thinking about Controller View component composition allows for cleaner data management:

  • Provides a single, logical place to interact with Flux/Redux stores.
  • Always know where data is coming from and where the source of truth is.
  • Data flow is controlled for all child component by setting props on children components.

I'll follow up with another post on component creation techniques to talk more about Controller Views and Presentation Components.

Duncan Leung

Front End Developer at iHerb.com

Irvine, CA

Subscribe to Duncan Leung: Javascript and Front End Development

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!