Components, the war horses of React.

In the previous post we learned what React is and its main traits. You also have seen how to create React elements with plain Javascript using the React API, and with an optional syntax named JSX. But that’s not all, and certainly not the reason why you have decided to learn React. You want to build dashing and highly interactive user interfaces that reacts to user and server events, and yet remain maintainable and easy to reason about. You can accomplish this by composing components. Before we get to that let’s take a look at how we can create a basic custom component:

Some of the code in the preceding example should already look familiar to you, and given the generated DOM:

<div id=”app-container”>
<h1 data-reactroot class=”header”>I’m a custom component</h1></div>

You probably get the general idea. But…

What about React.createClass( ) and how it works?

React.createClass( ) is where you define your component’s look and feel and behavior. It’s a method that creates a ReactClass that can be passed as a type to the React.createElement( ) method. It takes as its parameter a specification object that encloses the component’s state and describes how the component is rendered. The specification object needs to have at least a render( ) method so that it returns a ReactElement or when you don’t want to render anything returns: null or false.

Note:
There are other ways to define a React component than React.createClass( ). Here I’m assuming no prior experience with EcmaScript 6 to lower the entry barrier and the cognitive load of the content.

But you might be wondering what are the advantages of wrapping the creation of a ReactElement inside a render( ) method if we can accomplish the same results just like this:

ReactDOM.render(
React.DOM.h1({className: 'header'}, "I’m a custom component"),
document.getElementById('app-container')
);

The benefit of having a method render( ) is that, like any other function, it can compute a complex logic and choose what value to return. In addition to this you can use the props and the state of the component in it. In the example above (react-first-component.html) we pass a property named “title” when creating the ReactElement, then this property is accessed via “this.props.title” in the render( ) method.

The ability to configure components using properties is a key factor in making React components reusable and composable. The props are passed from parent to child components and they can’t be changed from inside the child component. Props are owned by the parent.

In JSX, props are provided as tag attributes, from now on we will use JSX for sake of simplicity and readability. Let’s build a simple contact list with a parent component “ContactList” composed by “ContactItem” components:

Now that you have seen how to compose components and how to pass data from parent to children components you might be concerned about how to properly validate these props. Don’t worry, React got you covered, in your components you can add a property called propTypes to declare the list of properties that your components accepts and their types. Let’s add props validation to the previous example:

Is pretty straightforward “email: React.Proptypes.string.isRequired” asks for a property named email that has to be a string and is non-optional . If you forget to pass this property you get a warning in the console.

Although propTypes is optional I strongly recommend its use. The two main benefits propTypes brings are:

  1. You no longer have to write defensive code because React does the validation of the properties values for you at runtime.
  2. You can use it to document your components. You no longer need to look around the source code of the render( ) method to figure out what properties needs to be provided.

What about state?

So far the components we have created are stateless, the data we provided doesn’t change, they are only concerned about render data, they are presentational. On the other hand, state is reserved for interactivity, when the data changes over time.

It is a common best practice to create several stateless components that just render data, and have a stateful component wrapping them that passes its state to the children via props. This way you can encapsulate all the interaction logic in one place — the stateful component — , while the stateless components take care of rendering data in a declarative way.

How does state works?

When you create a component via React.createClass( ) you can access the state via this.state in the context of the specification object. You can also provide a getInitialState( ) method so that it returns an object that represents the component initial state. Then you can mutate the state by calling:

this.setState(data, callback);

This method merges data into this.state and re-renders the component — this happens very fast due to React’s use of virtual DOM — . When the component finishes re-rendering, the optional callback if provided is called. You’ll rarely need to use this callback since React will take care of keeping your user interface up to date.

To illustrate this process lets add a search functionality to the previous example:

To properly understand this last example there are several things to notice. We created a new stateless component named Search where we returned a ReactElement representing a text input:

<input 
type=’text’
placeholder=’search’
value={this.props.text}
onChange={this.handleTextChange} />

The type, placeholder and value attributes are self-explanatory, the same as regular HTML. The confusion begins when you see:

onChange={this.handleTextChange}

The onChange attribute is similar to how you would normally do in HTML but camel cased, another common example could be onClick instead of onclick. React ensures that all events behave consistently across all browsers by implementing a synthetic event system. React doesn’t actually attach event handlers to the nodes themselves, instead when React starts up, it starts listening for all events at the top level using a single event listener, and when your component is mounted the event handlers are added to an internal mapping. Then when an event occurs, React knows how to dispatch it using this mapping. When your component is unmounted the event handlers are removed from the internal mapping so you don’t need to worry about memory leaks.

The other thing to notice about event handlers is that are automatically bounded to its component instance (except when using ES6 class syntax), and React does this in a very efficient way.

Now that we have a clearer understanding of the stateless components involved in the example — ContactItem and ContactList remain the same — we can dive into App component, the root component of our React application.

App is a stateful component, it has an initial state that can be mutated via setState( ), when this happens it forces a re-render and passes new props based on the new state to its children so that they are forced to re-render too. Notice that we call setState( ) in the method changeText( ) that we pass as a property to the Search component, this method is automatically bound like the event handlers. When the text changes in the Search component it triggers the onChange event and is called the function that were passed down by App then the state is mutated and happens the process previously described. This process illustrate the unidirectional data flow that React favors.

Conclusions

In a React application everything is made of components, you can mix and match them as you wish to decompose the most complex UI logic. You can truly commit to the “divide and conquer” tenet, where no particular component needs to be specially complex.

Components certainly are the war horses of React.

What’s next?

In my next posts I’ll cover other features related to React components, such as its lifecycle methods, how to integrate them with third party libraries and how to avoid re-renders. Also we will learn when a component is considered pure and a different way of declare it. All of these and more.

I hope you find this post useful and don’t miss the next one!!!