React Properties

Last time we looked at components, which are the building blocks of any React-powered interface. Today we will continue to explore them, with a focus on how to customise them.

There are a few ways in which React components can be customised, but we’re going pay particular attention to properties. Properties are to React components what attributes are to HTML elements. In fact, their most basic use is in the form of attributes, in JSX.

You can find the accompanying source-code, for this tutorial, at: https://github.com/formativ/tutorial-react-properties.
Please post any errors you find, or questions you have as comments on this article or as issues on GitHub.
Thanks to Christoph Pojer and Paul O’Shannessy for helping to improve this!

Defining Properties

If you’re familiar with HTML (and you really should be for this tutorial to make sense) then you know that HTML elements can be customised by the attribute values contained in the opening tag.

Given a simple component:

/**
* @jsx React.DOM
*/

var InterfaceComponent = React.createClass({
render : function() {
return <div>hello world!</div>;
}
});

React.renderComponent(
<InterfaceComponent />,
document.body
);

We can change the behaviour of this component by altering the contents of the render() method. What if we wanted the behaviour to changed, based on external information? We can use properties!

/**
* @jsx React.DOM
*/

var InterfaceComponent = React.createClass({
render : function() {
return <div>hello {this.props.name}!</div>;
}
});

React.renderComponent(
<InterfaceComponent name="chris" />,
document.body
);

I wasn’t kidding when I said that properties were like attributes. In JSX they can be defined as attributes. Let’s break this example down:

React.renderComponent(
<InterfaceComponent name="chris" />,
document.body
);

When we provide a name attribute (and value) this gets passed along to the component. If you come from a history of Object Oriented Programming languages, you may think that these properties are passed to a constructor and that you need to manage them from there. Don’t fall into this trap!

They are actually passed to a constructor, but you should never try to override this behaviour with your own constructor functionality. You should only use these values from this.props:

var InterfaceComponent = React.createClass({
render : function() {
return <div>hello {this.props.name}!</div>;
}
});

You may be wondering what the curly braces are for. They drop out of the HTML-like syntax into JavaScript evaluation mode. We’ll see how that can be used to great effect in future tutorials, but what’s important for now is that defined properties can be accessed via this.props.

You can also define hyphen-separated property names. You will have to use array access to pull them out of this.props though.

Supported Elements

So far we’ve used div, span and our own components. It’s helpful to know which HTML elements have been implemented as React components (and are therefore instantiable with JSX element syntax).

Here’s a list of supported HTML elements:

a abbr address area article aside audio b base bdi bdo big blockquote body br button canvas caption cite code col colgroup data datalist dd del details dfn div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hr html i iframe img input ins kbd keygen label legend li link main map mark menu menuitem meta meter nav noscript object ol optgroup option output p param pre progress q rp rt ruby s samp script section select small source span strong style sub summary sup table tbody td textarea tfoot th thead time title tr track u ul var video wbr

Supported Attributes

As you might expect, most of the attributes that can be found in regular HTML are supported in JSX:

accept accessKey action allowFullScreen allowTransparency alt autoCapitalize autoComplete autoFocus autoPlay cellPadding cellSpacing charSet checked className colSpan content contentEditable contextMenu controls data dateTime dir disabled draggable encType form frameBorder height hidden href htmlFor httpEquiv icon id label lang list loop max maxLength method min multiple name pattern placeholder poster preload radioGroup readOnly rel required role rowSpan scrollLeft scrollTop selected size spellCheck src step style tabIndex target title type value width wmode

You may notice, from this list, that attributes usually specified in hyphen-case (HTML) are supported in camelCase (JSX). That’s not to say that you can only use camelCase for your own attributes. It’s simply a design decision which allows for this.props.* access.

There are a few exceptions to the way HTML attributes usually work (other than the case difference we’ve already covered):

  1. The style attribute doesn’t accept strings. You can specify a JavaScript object with keys that correspond to the camelCase CSS property names. We’ll see an example of this shortly.
  2. Events can be assigned (following the W3C specification) using attributes like onClick and onChange.
  3. the onChange event is triggered when the element’s value changes. This differs from some browsers which need the element to blur before onChange is triggered.

There are other differences, but we’ll look at them as we continue in the series.

You can find out more support details at: http://facebook.github.io/react/docs/tags-and-attributes.html.

Validating Properties

There’s a handy property you can set (on new component definitions) which will allow you to control the presence and/or type of properties:

/**
* @jsx React.DOM
*/

var InterfaceComponent = React.createClass({
propTypes: {
name : React.PropTypes.string,
visible : React.PropTypes.bool.isRequired,
before : function(props, propName, componentName) {
if (!(propName in props)) {
throw new Error("before must be set.");
}

var now = new Date();

if (now.getTime() >= props[propName].getTime()) {
throw new Error("before must be set to a later date.");
}
}
},
render : function() {
return <div>hello {this.props.name}!</div>;
}
});

React.renderComponent(
<InterfaceComponent
name="chris"
visible={true}
before={new Date(Date.now() + 1000)} />,
document.body
);

You can validate the type of properties by providing any of the types in React.PropTypes.*. To make a property required, append .isRequired to the type. You can also define a callback function in which you perform specific validation against the provided properties. In this cause I check that the before property is provided and that it is a date beyond the current date/time.

You can also use React.PropTypes.instanceOf(SomeClass) to compare a property against a defined class, but you shouldn’t need to use this as much as the standard data types and callback functions.
You can find out more about property type validation at: http://facebook.github.io/react/docs/reusable-components.html.

Setting Property Defaults

Let’s look at how to set default property values, that can be overridden by properties passed in initialisation:

/**
* @jsx React.DOM
*/

var InterfaceComponent = React.createClass({
getDefaultProps : function() {
return {
"firstName" : "chris",
"lastName" : "pitt"
};
},
render : function() {
return <div>
hello {this.props.firstName + " " + this.props.lastName}
</div>;
}
});

React.renderComponent(
<InterfaceComponent />,
document.body
);

The getDefaultProps() method must return an object. The contents of that object are up to you, but they will get overwritten by properties provided in initialisation.

You can find out more about default properties at: http://facebook.github.io/react/docs/component-specs.html#getdefaultprops.

Transferring Properties

When you are working with multiple components, in a hierarchy, there may be occasion for sending properties down the structural tree. This has the benefit of reducing code duplication…

/**
* @jsx React.DOM
*/

var ChildComponent = React.createClass({
render : function() {
return <div style={{
color : this.props.color,
background : this.props.background
}}>
I am {this.props.color}
</div>
}
});

var ParentComponent = React.createClass({
render : function() {
return this.transferPropsTo(
<ChildComponent background={null} />
);
}
});

React.renderComponent(
<ParentComponent color="blue" background="red" />,
document.body
);

In this example we can see how the transferPropsTo() method will pass all the properties of a parent component to a child component. That is unless we explicitly set the value of a child component’s property, as we did for background.

Be careful when using this approach to passing properties around. You may inadvertently create a dependency between your parent and child components. It’s usually better just to explicit pass properties when instantiating child components.

Conclusion

Properties are what turn dull components into configurable interface elements. They are key to component reuse and help immensely with nested component design. We’ve seen most of how properties can be used, but there’s still loads more to components. Keep reading.

If you enjoyed this tutorial; it would be helpful if you could click the Recommend button and share it with other developers.