Learning React Js
Learning React Js
React.js
Table of Contents
Introduction 0
JSX 1
What is JSX 1.1
Benefits of JSX 1.2
Composite Components 1.3
How is JSX different than HTML 1.4
Component 2
Lifecycle Methods 2.1
Instantiation 2.2
Lifetime 2.3
Cleanup 2.4
Anti Pattern 2.5
Data Flow 3
Event Handling 4
Composing Components 5
Mixins 6
Dom Manipulation 7
Redux 8
2
Learning React.js
Background
React started as a port of a PHP framework by Facebook called XHP. Being a PHP
framework, XHP was designed to render our the entire page every time a request is made.
React was born to bring the PHP style work flow to client side applications.
React has no opinions on AJAX, routing, storage, or how to structure your data. It is not a
Model-View-Controller framework; if anything, it is the V in MVC. This narrow scope gives
you the freedom to incorporate React into a wide variety of systems. In fact it has been used
to render views in several popular MVC frameworks.
Like high-performance 3D game engines, React is built around render functions that take the
state of the world and translate it into a virtual representation of the resulting page.
Whenever React is informed of a state change, it re-runs those functions to determine a new
virtual representation of the page, then automatically translates that result into the necessary
DOM changes to reflect the new presentation.
Introduction 3
Learning React.js
JSX
React embraces the idea that markup, and the code which generates it, are inherently tied
together. This is expressed in React components by rendering the markup directly within
Javascript, using the full expressive power of the language.
React introduces an optional markup language remarkably similar to HTML. For example, a
function call in plain React to create a header might look like this.
But with JSX it becomes much more familiar and terse looking markup.
<h1 className="question">Questions</h1>
In this chapter we’ll walk you through the benefits of JSX and how to use it, along with some
of the gotchas that separate it from HTML. Remember, JSX is optional. If you choose not to
employ JSX you can skip to the end of the chapter for tips on using React without it.
React Without JSX All JSX markup is eventually transformed into simple JavaScript function
calls. So JSX is not necessary for using React.
It Functions All The Way Down The pattern for creating a component is simple. It’s just a
function, after all. HTML tagNames are defined in the React.DOM namespace. So creating a
div is as simple as calling the function.
React.DOM.div();
//
The first argument to a component function is the props object. So customizing the attributes
of a div would look like the following code. Each key in the props object maps to the attribute
name on the rendered div element.
React.DOM.div({className: "divider"});
//
Child nodes are passed in as optional arguments after the props object. Using our divider
example from above, which as two child nodes, we can render it as raw JavaScript with the
text node and hr component passed in as the second and third arguments, respectively.
JSX 4
Learning React.js
//
Label Text
Shorthand Writing React.DOM.div can be tedious after a while. It can be convenient to save
a reference using a shorter variable name, e.g. R. Thus we can express the above div a bit
more tersely.
var R = React.DOM; //... R.div( {className: "divider"}, "Label Text", R.hr() ); Or, if you prefer
to access the component as top-level variables you can reference them directly.
var div = React.DOM.div; var hr = React.DOM.hr; //... div( {className: "divider"}, "Label
Text", hr() ); Further Reading & References Even if you don’t like the idea of markup in your
Javascript, hopefully you can now appreciate how JSX offers a solution to the intimate
relationship between your Javascript and the markup it renders. Its growing popularity has
earned JSX its own spec offering a deep technical definition, and there are a few tools to
help you experiment with it if you’re still uncertain or confused about how it works.
The Official JSX Spec In September of 2014 Facebook released an official spec for JSX,
stating its rationale for creating JSX, along with technical details of the syntax.
In-Browser Experimenting There are also a number of tools for experimenting with JSX. The
React docs Getting Started page links to JSFiddle playgrounds with and without JSX.
http://facebook.github.io/react/docs/getting-started.html
And React comes with a JSX Compiler Service that transforms JSX into plain Javascript in-
browser.
http://facebook.github.io/react/jsx-compiler.html
JSX 5
Learning React.js
What is JSX
JSX stands for JavaScript XML — an XML-like syntax for constructing markup within React
components. (React works without JSX.)
What is JSX 6
Learning React.js
Benefits of JSX
1. JSX is easier to visualize than javascript functions
2. The markup is more familiar to designer and the rest of your team
3. Your markup becomes more semantic, more meaningful.
Easy to Visualize
Notice that its intent is more clear and readable in JSX format.
Plain Javascript
render: function () {
return React.DOM.div({className:"divider"},
"Label Text",
React.DOM.hr()
);
}
JSX Markup
render: function () {
return <div className="divider">
Label Text<hr />
</div>;
}
Which brings us to another key benefit of JSX: it’s easier for non-programmers already
familiar with html to work with it.
Familiarity
Many development teams include non-developers, from UI & UX designers who are familiar
with html to quality-assurance teams responsible for thoroughly testing the product.
JSX makes a great way to represent and visualize this structure in a compact and succinct
way.
Semantics
Benefits of JSX 7
Learning React.js
Along with familiarity, JSX transforms your javascript code into more semantic, meaningful
markup. This allows you the benefit of declaring your component structure and information
flow using an HTML-like syntax, knowing it will transform into simple javascript functions.
React defines all the HTML elements you’d expect in the React.DOM namespace. It also
allows you to use your own, custom components within the markup.
<div className="divider">
<h2>Questions</h2><hr />
</div>
However, after wrapping this in a Divider React component you can use it you would any
other html element, with the added benefit of markup with richer semantics.
<Divider>Questions</Divider>
Benefits of JSX 8
Learning React.js
Composite Components
Setup
While JSX allows you to express your components using markup, eventually it must be
transformed into Javascript.
In order for the JSX transform to know it should operate on a file you must insert the /* @jsx
React.DOM / pragma at the top of each file containing JSX. Without this JSX will not know it
should process the file for React.
The approach has a few benefits such as: The transformer can ignore all files without this
pragma It allows JSX to live beside non-JSX JavaScript files
All of your custom components, however, must be declared within the scope of your file,
otherwise the React will not know how to resolve the function.
Now that you’ve seen how to set up a JSX file you are ready to define a custom component
using JSX.
Composite Components 9
Learning React.js
Child Nodes
So the goal here is to express the divider in JSX similarly, like this:
<Divider>Questions</Divider>
React captures all child nodes between the open and close tags in an array on the
component’s props, this.props.children. In this example this.props.children ===
["Questions"].
Now you can use the component like you would any html element.
<Divider>Questions</Divider>
<div className="divider">
<h2>Questions</h2><hr />
</div>
Composite Components 10
Learning React.js
Attributes
In HTML we set the attributes of each node inline, like this:
JSX implements attributes in the same manner, You do this by wrapping a javascript variable
in curly-brackets instead of quotes.
For more complex situations you can set an attribute to the result of a function call.
Conditionals
React embraces the idea that a component’s markup and the logic that generate it are
inherently tied together. This means you have the full logical power of javascript at your
fingertips, such as loops and conditionals.
It can be tricky to add conditional logic to your components since if/else logic is hard to
express as markup. Adding if statements directly to JSX will render invalid JavaScript:
...
render: function () {
return <div className={
this.state.isComplete ? 'is-complete' : ''
}>...</div>;
}
...
While the ternary operator works well for text, it can be cumbersome and difficult to read
when you want to use a React component in either case. For these situations it is better to
use the following methods.
Using a variable
...
getIsComplete: function () {
return this.state.isComplete ? 'is-complete' : '';
},
render: function () {
var isComplete = this.getIsComplete();
return <div className={isComplete}>...</div>;
}
...
...
getIsComplete: function () {
return this.state.isComplete ? 'is-complete' : '';
},
render: function () {
return <div className={this.getIsComplete()}>...</div>;
}
...
Non-DOM Attributes
The following attributes are reserved words in JSX.
key
ref
dangerouslySetInnerHTML
Keys
key is an optional unique identifier. During runtime a component might move up or down the
component tree, for example as the user performs a search or items are added or removed
from a list. When this happens you component might be needlessly destroyed and
recreated.
By setting a unique key on a component that remains consistent throughout render passes
you inform React so it more intelligently decides when to reuse or destroy a component,
improving rendering performance. Then when two items already in the DOM switch positions
React can match the keys and move them without completely re-rendering their DOM.
References
ref allows parent components to keep a reference to child components available outside of
the render function.
You define a ref in JSX by setting the attribute to the desired reference name.
...
render: function () {
return <div>
<input ref="myInput" ... />
</div>;
}
...
And later you can access this ref by using this.refs.myInput anywhere in your component.
The object you access through this ref is called a backing instance. It’s not the actual DOM,
but a description of the component React uses to create the DOM when necessary. To
access the actual DOM node you use this.refs.myInput.getDOMNode().
For more detail see the discussion on parent/child relationships vs ownership in chapter 4.
...
render: function () {
var htmlString = {
__html: "<span>an html string</span>"
};
return <div dangerouslySetInnerHTML={htmlString} ></div>;
}
...
Events
Event names are normalized across all browsers and are represented camelCased. For
example change becomes onChange, and click becomes onClick. When capturing an event
in JSX it’s as simple as assigning the property to a method on the component.
...
handleClick: function (event) {...},
render: function () {
return <div onClick={this.handleClick}>...</div>
}
...
Note that React automatically binds all of a component’s methods, so you never need to
manually bind the context.
...
handleClick: function (event) {...},
render: function () {
// anti-pattern - manually binding the function context
// to a component instance is unnecessary in React.
return <div onClick={this.handleClick.bind(this)}>...</div>
}
...
For more details on the event system in React reference the chapter on Forms.
Special Attributes
Because JSX transforms to plain javascript function calls there are a few keywords we
cannot use — class and for.
To render a custom class use className. This might seem odd if you’re used to HTML, but
it is more consistent with vanilla javascript, where we can access the class of an element
using elem.className.
Styles
Lastly we come to the inline style attribute. React normalizes all styles to camelCased
names, consistent with the DOM style JavaScript property.
To define a custom style attribute simply pass a JavaScript object with camelCase property
names and the desired css values.
var styles = {
borderColor: "#999",
borderThickness: "1px"
};
React.renderComponent(<div style={styles}>...</div>, node);
Component
Chapter 3. Component Lifecycle React components are simply state-machines. Their output
represents the DOM for a given set of props and state. Throughout a component’s lifecycle,
as it’s props or state change, its DOM representation might change too. As noted in the
chapter on JSX, a component is just a Javascript function; for a given input it will always
return the same output.
React provides lifecycle hooks for a component to respond to various moments — its
creation, lifetime, and teardown. We’ll cover them here in order of their appearance — first
through instantiation, then through the components life and finally as the component is torn-
down.
Component 16
Learning React.js
Lifecycle Methods
Lifecycle Methods React has relatively few lifecycle methods, but they are very powerful.
React offers you all of the methods required to control the props and state of your app
throughout its lifecycle. Lets take a look at each in order as they get called on your
component.
The lifecycle methods called the first time an instance is created, vs each subsequent
instance, varies slightly. For your first use of a component class you’ll see these methods
called, in order:
getDefaultProps
getInitialState
componentWillMount
render
componentDidMount
For all subsequent uses of that component class you will see the following methods called,
in order. Notice getDefaultProps is no longer in the list.
getInitialState
componentWillMount
render
componentDidMount
As the app state changes and your component is affected you will see the following methods
called, in order:
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
And lastly, when you are finished with the component you will see componentWillUnmount
called, giving your instance the opportunity to clean-up after itself.
Now we’ll cover each of these three stages: instantiation, lifetime, and cleanup in turn.
Lifecycle Methods 17
Learning React.js
Instantiation
Instantiation
As each new component is created and first rendered there are series of methods you can
use to setup and prepare your components. Each of these methods has a specific
responsibility, as described here.
getDefaultProps
This method is called only once for the component class. The object returned is used to set
the default values for any new instances when they are not specified by the parent
component.
It is important to note that any complex values, such as objects and arrays, will be shared
across all instances — they are not copied or cloned.
getInitialState
Called exactly once for each instance of your component, here you get a chance to initialize
the custom state of each instance. Unlike getDefaultProps this method is called once each
time an instance is created. At this point you have access to this.props.
componentWillMount
Invoked immediately before the initial render. This is the last chance to affect the component
state before the render method is called.
render
Here you build the virtual DOM that represents your components output. Render is the only
required method for a component and has specific rules. The requirements of the render
method are as follows:
There can only be one top-level component (you cannot return an array of elements)
It must be pure, meaning it does not change the state oc modify the DOM output
The result returned from render is not the actual DOM, but a virtual representation that
React will later diff with the real DOM to determine if any changes must me made.
componentDidMount
Instantiation 18
Learning React.js
After the render is successful and the actual DOM has been rendered you can access it
inside of componentDidMount via this.getDOMNode().
This is the lifecyle hook you will use to access the raw dom. For example, if you need to
measure the height of the rendered output, manipulate it using timers, or run a custom
jQuery plugin, this is where you’d hook into.
Instantiation 19
Learning React.js
Lifetime
At this point your component has been rendered to the user and they can interact with it.
Typically this involves one of the event handlers getting triggered by a click, tap or key event.
As the user changes the state of a component, or the entire app, the new state flows through
the component tree and you get a chance to act on it.
componentWillReceiveProps
The props of a component can change at any moment through the parent component. When
this happens componentWillReceiveProps is called and you get the opportunity to change
the new props object and update the state.
For example, within our sample survey application we have an AnswerRadioInput that
allows users to toggle a radio input. The parent component is able to change this boolean
value and we can respond to it like this, updating our own internal state based on the
parent’s input props.
Since this method is called before the props are applied to the component you have the
opportunity to affect the props as well. As an example, if you required a certain prop to be a
boolean you can enforce that here, and the new value will be applied to the component
props.
componentWillReceiveProps: function(nextProps) {
// coerce the `checked` value to a boolean
nextProps.checked = !!nextProps.checked;
}
shouldComponentUpdate
React is fast. But you can make it even faster using shouldComponentUpdate to optimize
exactly when a component renders.
Lifetime 20
Learning React.js
If you are certain that the new props or state will not require your component or any of its
children to render, return false.
This method is not called during the initial render or after using forceUpdate.
By returning false you are telling react to skip calling render, and its before and after hooks
componentWillUpdate and componentDidUpdate.
This method is not required and for most purposes you will not need to use it during
development. Premature use of this method can lead to subtle bugs, so it’s best to wait until
you can properly benchmark your bottlenecks before choosing where to optimize.
If your careful to treat state as immutable and only read from props and state in your render
method then feel free to override shouldComponentUpdate to compare the old props and
state to their new replacements.
Another performance-tuning option is the PureRenderMixin provided with the React addons.
If your component is pure, meaning it always renders the same DOM for the same props &
state, this mixin will automatically use shouldComponentUpdate to shallowly compare props
and state, returning false if they match.
componentWillUpdate
Note you cannot update state or props in this method. You should rely on
componentWillReceiveProps for updating state during runtime.
componentDidUpdate
Similar to componentDidMount this method gives you an opportunity to update the rendered
DOM.
Lifetime 21
Learning React.js
cleanup
Teardown
Once React is done with a component it must be unmounted from the DOM and destroyed.
You are provided with a single hook to respond to this moment, performing any cleanup and
teardown necessary.
componentWillUnmount
Lastly we have the end of a components life as it’s removed from the component heirarchy.
This method is called just prior to your component being removed and gives you the chance
to clean up. Any custom work you might have done in componentDidMount, such as
creating timers or adding event listeners should be undone here.
Cleanup 22
Learning React.js
Anti Pattern
Anti Pattern — Calculated Values as State Given the possibility of using getInitialState to
create state from this.props it’s worth noting an anti-pattern here. React is very concerned
with maintaining a single source of truth. Its design makes duplicating the source of truth
more obvious, one of React’s key strengths.
You can identify this anti-pattern when it’s impossible to know inside of your render function
if your state value is out-of-sync with the prop it’s based from. // Anti-pattern. Calculated
values should not be stored as state. getDefaultProps: function () { return { date: new Date()
}; }, getInitialState: function () { return { day: this.props.date.getDay() } }, render: function () {
return
Day: {this.state.day}
; } The correct pattern is to calculate the values at render-time. This guarantees the
calculated value will never be out-of-sync with the props it’s derived from.
Day: {day}
; } However, if your goal is not synchronization, but is to simply initialize the state, then it is
proper to use props within getInitialState. Just be sure to make your intentions clear, for
example prefix the prop with initial.
{this.props.value}
} React’s lifecycle methods provide well-designed hooks into the life of your components. As
state machines, each component is designed to output stable, predictable markup
throughout it’s life.
However no component lives in isolation. As parent components push props into their
children, and as those children render their own child components, you must carefully
consider how your data flows through the app. How much does each child really need to
know about? Who owns the app state? This is the subject of our next chapter: Data Flow.
Anti Pattern 23
Learning React.js
Anti Pattern 24
Learning React.js
Data Flow
Chapter 4. Data Flow In React, data flows in one direction only: From the parent to the child.
This makes components really simple and predictable. They take props from the parent and
render. If a prop is changed at the top level component, React will propagate that change all
the way down the component tree and re-render all the components that used that property.
Components can also have internal state, which should only be modified within the
component.
React components are inherently simple and you can consider them as a function that take
props and state and output HTML.
What “props” are What “state” is When to use “props” and when to use “state” Props “props”,
short for “properties" are passed to a component and can hold any data you’d like.
Add survey It can also be set with the {} syntax, which injects JavaScript and allows you to
pass in variables of any type:
{survey.title} It’s possible with the transferPropsTo method to pass all props received to a
child component, but it is advised against using this function as it encourages tight coupling.
Instead explicitly copy over the props from the parent to the child component:
// vs the explicit var ListSurveys = React.createClass({ render: function () { return ; } }); Props
are useful for event handlers as well:
Data Flow 25
Learning React.js
PropTypes React provides a way to validate your props, through a config object defined on
your component:
You are not required to use propTypes in your application, but they provide a good way to
describe the API of your component.
state Each component in a React can house state. State differs from props in that it is
internal to the component.
State is useful for deciding a view state on an element. Consider the component used for
collecting survey answers:
{this.props.label}
); } }); Here we use state to track if the checkbox should be checked or not.
State is altered via the setState method and can have a default value provided the
getInitialState method as shown above. When ever setState is called within the component
the render method is called and if there were changes to the output of the render function,
the DOM will be updated and finally the user will see a change in their browser.
Data Flow 26
Learning React.js
State will always make your component more complex, if you isolate your state to certain
components you application becomes easier to debug and reason about.
What belongs in state and what belongs in props Don’t store computed values or
components in state, instead focus on simple data that is directly required for the component
to function, like our checked state from earlier. Without it we couldn’t check and uncheck the
checkbox. This could also be a boolean for showing the options of a dropdown, or the values
of an input field.
Try not to duplicate prop data into state. When possible consider props the source of truth.
Data Flow 27
Learning React.js
Event Handling
Chapter 5. Event Handling When it comes to user interfaces, presenting is only half the
equation. The other part is responding to user input, which in JavaScript means handling
user-generated events.
React’s approach to event handling is to attach event handlers to components, and then to
update those components’ internal states when the handlers fire. Updating the component’s
internal state causes it to re-render, so all that is required for the user interface to reflect the
consequences of the event is to read from the internal state in the component’s render
function.
Although it is common to update state based solely on the type of the event in question, it is
often necessary to use additional information from the event in order to determine how to
update the state. In such a case, the Event Object that is passed to the handler will provide
extra information about the event, which the handler can then use to update the internal
state.
Between these techniques and React’s highly efficient rendering, it becomes easy to
respond to user’s inputs and to update the user interface based on the consequences of
those inputs.
Attaching Event Handlers At a basic level, React handles the same events you see in
regular JavaScript: MouseEvents for click handlers, Change events when form elements
change, and so on. The events have the same names you would see in regular JavaScript,
and will trigger under the same circumstances.
React’s syntax for attaching event handlers closely resembles HTML’s. For example, in the
SurveyBuilder, the following code attaches an onClick handler to the Save button.
Save When the user clicks the button, the button’s handleSaveClicked method will run.
That method will contain the logic necessary to resolve the Save action.
If you are not using JSX, you instead specify the handler as one of the fields in the options
object. For example:
Most of these work without any extra effort, but touch events must be manually enabled by
calling this:
Event Handling 28
Learning React.js
Start with a render function which registers some event handlers based on the HTML5 Drag
and Drop API.
Modules
<div className='survey-canvas col-md-9'>
<div
className={'drop-zone well well-drop-zone'}
onDragOver={this.handleDragOver}
onDragEnter={this.handleDragEnter}
onDragLeave={this.handleDragLeave}
onDrop={this.handleDrop}
>
Drag and drop a module from the left
</div>
</div>
</div>
</div>
);
});
The DraggableQuestions component will render the menu of question types, and the handler
methods will take care of resolving drag and drop actions.
Rendering Based on State One thing the handler methods will need to do is to expand some
running list of the questions added so far. To do this, you will need to make use of the
internal state object that every React component contains. It begins as null by default, but
can be initialized to something sane with a component’s getInitialState() method, like so:
getInitialState: function () { return { dropZoneEntered: false, title: '', introduction: '', questions:
[] }; } This establishes a sane baseline for the state: a blank title, a blank introduction, an
empty list of questions, and a value of false for dropZoneEntered - indicating that the user is
not currently dragging anything over the drop zone.
From here, you can read from this.state in the render method in order to display the current
values of each of these to the user.
Event Handling 29
Learning React.js
return (
<div className='survey-editor'>
<div className='row'>
<aside className='sidebar col-md-3'>
<h2>Modules</h2>
<DraggableQuestions />
</aside>
<Divider>Questions</Divider>
<ReactCSSTransitionGroup transitionName='question'>
{questions}
</ReactCSSTransitionGroup>
<div
className={'drop-zone well well-drop-zone ' + dropZoneEntered}
onDragOver={this.handleDragOver}
onDragEnter={this.handleDragEnter}
onDragLeave={this.handleDragLeave}
onDrop={this.handleDrop}
>
Drag and drop a module from the left
</div>
<div className='actions'>
<button className="btn btn-save" onClick={this.handleSaveClicked}>Save</button>
</div>
</div>
</div>
</div>
);
} As with this.props, the render function can change as little or as much as you like
depending on the values of this.state. It can render the same elements but with slightly
different attributes, or a completely different set of elements altogether. Either works just as
well.
Event Handling 30
Learning React.js
Updating State Since updating a component’s internal state causes the component to re-
render, the next thing to do is to update that state in the drag handler methods. Then render
will run again, it will read from the current value of this.state to display the title, introduction,
and questions, and the user will see that everything has been updated properly.
There are two ways to update a component’s state: the component’s setState method and
itsreplaceState method. replaceState overwrites the entire state object with an entirely new
state object, which is rarely what you want. Much more often you will want to use setState,
which simply merges the object you give it into the existing state object.
For example, suppose you have the following for your current state:
Calling this.replaceState({title: "Fantastic Survey 2.0"}) would instead replace the entire state
object with the new object {title: "Fantastic Survey 2.0"}, erasing
this.state.dropZoneEntered,this.state.introduction, and this.state.questions altogether. This
would likely break the render function, which would expect this.state.questions to be an
array instead of undefined.
Using this.setState, you can now implement the handler methods from earlier.
this.setState({
questions: questions,
dropZoneEntered: false
});
} It’s important never to alter the state object by any other means than calling setState
orreplaceState. Doing something like this.state.saveInProgress = true is generally a bad
idea, as it will not inform React that it might need to re-render, and might lead to surprising
results the next time you call setState.
Event Handling 31
Learning React.js
Event Objects Many handlers simply need to fire in order to serve their purposes, but
sometimes you need more information about the user’s input.
{this.props.label}
</div> ); } }); React’s event handler functions are always passed an event object, much in
the same way that a vanilla JavaScript event listener would be. Here, the handleComplete
method takes an event object, from which it extracts the current value of the textarea by
accessing event.target.value. Using event.target.value in an event handler like this is a
common way to get the value from a form input, especially in an onChange handler.
Rather than passing the original Event object from the browser directly to the handler, React
wraps the original event in a SyntheticEvent instance. A SyntheticEvent is designed to look
and function the same way as the original event the browser created, except with certain
cross-browser inconsistencies smoothed over. You should be able to use the SyntheticEvent
the same way you would a normal event, but in case you need the original event that the
browser sent, you can access it via the SyntheticEvent’s nativeEvent field.
Summary The steps to reflect changes from user input in the user interface are simple:
Attach an event handler to a React component In that event handler, update the
component’s internal state. Updating the component’s state will cause it to re-render. Modify
the component’s render function to incorporate this.state as appropriate. So far you have
used a single component to respond to user interactions. Next you will learn how to
compose multiple components together, to create an interface that is more than the sum of
its parts.
Event Handling 32
Learning React.js
Composing Components
Chapter 6. Composing Components In traditional HTML the basic building block of each
page is an element. In React you assemble a page from components. You can think of a
React component as an HTML element with all the expressive power of JavaScript mixed in.
In fact with React the only thing you do is build components, just like an HTML document is
build with only elements.
Since the entirety of a React app is build using components, this whole book can be
described as a book about React components. Therefore in this chapter we won’t cover
everything to do with components. Rather you will be introduced to one specific aspect —
their composability.
A component is basically a JavaScript function that takes in props and state as its arguments
and outputs rendered HTML. They are typically designed to represent and express a piece
of data within your app so you can think of a React component as an extension of HTML.
Extending HTML React + JSX are powerful and expressive tools allowing us to create
custom elements that can be expressed using an HTML-like syntax. However they go far
beyond plain HTML, allowing us to control their behavior throughout their lifetime. This all
starts with the React.createClass method.
React favors composition over inheritance, which means we combine small, simple
components and data objects into larger, more complex components. If you’re familiar with
other MVC or object-oriented tools you might expect to find a React.extendClass method, as
I did. However, just as you don’t extend html dom nodes when building a web page, you
don’t extend React components. Instead you compose them.
Obviously a survey will be built around basic html form elements. You will be crafting our
survey answer components by wrapping the default html input elements and customizing
their behavior.
Composing Components 33
Learning React.js
Take a list of choices as input Render the choices to the user Only allow the user to select a
single choice We know html provides us some some basic elements to help us, namely the
“radio” type inputs and input groups. Thinking of it from the top-down our component
hierarchy will look something like this:
Assemble the HTML Let’s start by assembling the components from the bottom-up. React
pre-defines the input component for us in the React.DOM.input namespace. Therefore the
first thing you’ll do is wrap it in a RadioInput component. This component will be responsible
for customizing the generic input, narrowing it’s scope to behave like a radio button. Within
the accompanying sample app it is named AnswerRadioInput.
First create the scaffolding, which will include the required render method and the basic
markup to describe the desired output. You can already begin to see the composition pattern
as the component becomes a specialized type of input.
Label Text
); } }); Add Dynamic Properties
Nothing about our input is dynamic yet, so next you need to define the properties the parent
must pass into the radio input.
What value, or choice, does this input represent? (required) What text do we use to describe
it? (required) What is the input’s name? (required) We’ll might want to customize the id. We
might want to override the default value. Given this list you can now define the property
types for our custom input. Add these to the propTypes hash of the class definition.
Since this method is only called once for the class, not for each instance, we cannot provide
the id here — it must be unique for each instance. That will be solved using state below.
Composing Components 34
Learning React.js
can update the checked value at any time. Therefore we define the initial state.
{this.props.label}
); } }); Integrate into a Parent Component At this point you have enough of a component to
use it within a parent so you’re ready to build up the next layer, the
AnswerMultipleChoiceQuestion. The primary responsibility here is to display a list of choices
for the user to choose from. Following the pattern introduced above, let’s lay down the basic
html and the default props for this component.
{this.props.label}
...
</div> ); } }); In order to generate the list of child radio input components we must map over
the choices array, transforming each into a component. This is easily handled in a helper
function as demonstrated here.
{this.props.label}
{this.renderChoices()}
</div> ); } }); Now the composability of React is becoming more clear. You started with a
generic input, customized it into a radio input, and finally wrapped it into a multiple-choice
component — a highly refined and specific version of a form control. Now rendering a list of
choices is as simple as this:
The astute reader has probably noticed there is a missing piece — our radio inputs have no
way of communicating changes to their parent component. You need to wire up the
AnswerRadioInput children so the parent is aware of their changes and can process them
into a proper survey-result data payload. Which brings us to the parent/child relationship.
Composing Components 35
Learning React.js
Parent / Child Relationship At this point you should be able to render a form to the screen,
but notice that you have yet to give the components the ability to share user changes. The
AnswerRadioInput component does not yet have the ability to communicate with its parent.
The easiest way for a child to communicate with its parent is via props. The parent needs to
pass in a callback via the props, which the child calls it when needed.
First you need to define what AnswerMultipleChoiceQuestion will do with the changes from
it’s children. Add a handleChanged method and pass it into each AnswerRadioInput.
{this.props.label}
); } }); Wrap Up Now you’ve seen how React uses the pattern of composability, allowing you
to wrap html elements or custom components and customize their behavior for your needs.
As you compose components they become more specific and semantically meaningful. Thus
React takes generic inputs,
finally ending up with a single component to transform an array of data into a useful UI for
users to interact with.
Composition is just one way React offers to customize and specialize your components.
Mixins offer another approach, allowing you to define methods that can be shared across
many components. Next we show you how to define a mixin and how they can be used to
share common code.
Composing Components 36
Learning React.js
Mixins
Chapter 7. Mixins
What are Mixins? On the homepage of React we have this example of a timer component:
The lifecycle methods starting with “component”, e.g. “componentDidMount”, are called in
the order of the mixin array, and finally the componentDidMount on the component class
itself, if it exists.
Mixins 37
Learning React.js
have multiple intervals, and uoi can’t choose the function that handles the interval, and we
can’t terminate the interval manually without using the internal __interval property. To solve
this, our mixin can have a public api.
Here’s an example where we simply want to show the number of seconds since January 1st
2014. This mixin is a bit more code, but more flexible and powerful.
{Math.round((to-from) / 1000)}
); } });
Mixins are one of the most powerful tools for eliminating code repetition, and keeping your
components focused on what makes them special. They allow you to use powerful
abstractions, and some problems can’t be solved elegantly without them. Some noteworthy
examples:
a mixin which listens for events, and applies them to state (e.g. flux store mixin) an upload
mixin which handles XHR uploads, and applies the status and progress of uploads to state
‘layers’ mixin, which facilitates rendering children to the end of </body> (e.g. for modals)
Testing Now that you’ve learned how a mixin can be used in our component, an interesting
question becomes -- how do we unit test it? Turns out there are three options for testing a
mixin:
Test the mixin object directly Test the mixin which is included in a fake component Test the
mixin which is included in the real component using a shared behavior spec Testing the
mixin directly To test the mixin directly, you simply call the functions on the mixin object
directly and validate the behavior that way. This approach usually results in very fine grained
tests which will need stubs for any React.js methods called from within a function. Let’s give
this a try by starting with the simplest function in our mixin, componentDidMount:
/* @jsx React.DOM /
Mixins 38
Learning React.js
beforeEach(function(){
// WARNING: DON'T DO THIS!! IT WILL CAUSE ISSUES WHICH WE WILL DISCUSS BELOW
subject = IntervalMixin;
});
describe("componentDidMount", function(){
it("should set an empty array called __intervals on the instance", function(){
expect(subject.__intervals).toBeUndefined();
subject.componentDidMount();
expect(subject.__intervals).toEqual([]);
});
});
}); }); When we run this tests it passes fine. You might notice that you are using the
IntervalMixin as your subject, this is not a good idea because the componentDidMount
function is setting a variable on this, subject, which in this case will be the IntervalMixin
object. So when the next test runs, the IntervalMixin object has been polluted and will cause
weird failures. To see this in action, modify the spec to this:
...
beforeEach(function(){
// WARNING: DON'T DO THIS!! IT WILL CAUSE ISSUES WHICH WE WILL DISCUSS BELOW
subject = IntervalMixin;
});
describe("componentDidMount", function(){
it("should set an empty array called __intervals on the instance", function(){
expect(subject.__intervals).toBeUndefined();
subject.componentDidMount();
expect(subject.__intervals).toEqual([]);
});
it("should set an empty array called __intervals on the instance (testing for test pollution)", fun
expect(subject.__intervals).toBeUndefined();
subject.componentDidMount();
expect(subject.__intervals).toEqual([]);
});
});
Mixins 39
Learning React.js
}); }); And you will see the second test fails on the
expect(subject.__intervals).toBeUndefined(); line, because the test before had executed:
... beforeEach(function(){ subject = Object.create(IntervalMixin); }); ... Now that you’ve got a
test passing for componentDidMount, lets work on testing setInterval. The setInterval
function has three responsibilities:
be a pass-through to the real setInterval function save off the interval id number into an array
(so it can be cleared out later) return the interval id So those tests would look something like
this:
it("should call window.setInterval with the callback and the interval", function(){
expect(window.setInterval.callCount).toBe(0);
subject.setInterval(function(){}, 500);
expect(window.setInterval.callCount).toBe(1);
});
expect(subject.__intervals).toEqual([fakeIntervalId]);
});
expect(returnValue).toBe(fakeIntervalId);
});
});
Mixins 40
Learning React.js
... STUB OUT REACT.JS Notice how the above tests don’t need any React.js specific
functionality, so they will be vanilla jasmine tests. If your mixin functions start calling methods
which are provided by React.js (like this.setState({})), it is usually recommended to
spyOn(subject, "setState") to mock out the React.js specific functions which are used. This
allows you to keep your mixin test isolated to just the mixin object.
You might have noticed that testing the mixin directly results in tests which are very fine
grained. Sometimes this can be helpful when the behavior starts to grow in complexity, but
sometimes it can lead to a path where you are testing the implementation and not the
functionality. It also requires you to call any functions on the mixin in a specific order to
mimic React.js lifecycle callbacks, like how we had to call subject.componentDidMount(); in
the setInterval test. The next section will show a way to test a mixin without these
drawbacks.
Test the mixin which is included in a fake component To test a mixin with a fake component,
i.e. a “faux” component, you will need to define a React component in your test suite. The
fact the component is defined in the test suite makes it very clear that this component exists
for the sole purpose of testing and can’t be used in the production application. Below is an
example of our faux component. Notice how the functionality is simple so that we can keep
the tests simple which will help keep the intent of each tests clear. The only bit of “cruft” is
the render function which is required by React.
beforeEach(function(){
// Notice how the faux component is defined in the jasmine spec file. This is
// intentional. This expresses the intent that this react component exists
// for the sole purpose of testing this mixin.
FauxComponent = React.createClass({
mixins: [IntervalMixin],
render: function(){
return (<div>Faux components are all the rage!</div>);
},
myFakeMethod: function(){
this.setInterval(function(){}, 500);
}
});
});
}); Now that you’ve got your faux component, let’s write some tests:
Mixins 41
Learning React.js
it("should call window.setInterval with the callback and the interval", function(){
expect(window.setInterval.callCount).toBe(0);
subject.myFakeMethod();
expect(window.setInterval.callCount).toBe(1);
});
});
describe("unmounting", function(){
var subject;
beforeEach(function(){
spyOn(window, "setInterval").andReturn(555);
spyOn(window, "clearInterval");
subject = TestUtils.renderIntoDocument(<FauxComponent />);
subject.myFakeMethod();
});
... The first major difference with these specs, which render a faux component, versus the
specs which directly test the mixin, is that you need to first render said faux component and
then start operating against it to make your test assertions. While this difference is glaring,
there is a more subtle difference which can have a large effect on your tests: “Faux” has
tests for setInterval and unmounting, while “direct” has tests for setInterval,
componentDidMount, and componentWillUnmount.
That doesn’t sound like such a big deal, so who cares? For the answer for this, look at the
componentDidMount function. Setting up this.intervals provides no value in of itself, the
value is only used with the other functions. In the “direct mixin” spec, we are testing
the implementation of the function by asserting on this.intervals which is an
implementation detail, not functionality. In the “faux component” tests, we don’t need to test
the implementation of componentDidMount because it is implicitly tested in the setInterval
test when the component is rendered into the document.
Mixins 42
Learning React.js
WHICH ONE TO CHOOSE? In the two methods we have gone over so far, “direct” and
“faux”, one is not better than the other. It depends on the complexity and behavior of your
mixin for which one is better. One recommendation is to start with writing the “direct” spec,
because it’s the most focused and then if it becomes a pain to write, then switch it to a faux
spec (or do both). Don’t be afraid to just pick one option and let your tests tell you that you
are wrong.
Shared behavior spec The “faux” and “direct” approaches didn’t involve any of the
components from your real application, only the mixin itself. The last approach will test the
mixin via the real world components which will actually use that mixin -- this approach is
called the “shared behavior” spec. The first big difference with this approach is that our tests
are no longer located in the interval_mixin_spec.js, because the specs will be run by the
since_2014_spec.js. Let’s start there:
describe("Since2014", function(){ }); We’ve got our boilerplate for a Since2014 spec, so now
let’s add our “shared example spec”:
var componentClass;
Mixins 43
Learning React.js
...
var componentClass;
Mixins 44
Learning React.js
beforeEach(function(){
spyOn(window, "setInterval");
subject = TestUtils.renderIntoDocument(<componentClass />);
fakeFunction = function(){};
});
it("should call window.setInterval with the callback and the interval", function(){
expect(window.setInterval).not.toHaveBeenCalledWith(fakeFunction, jasmine.any(Number));
subject.setInterval(fakeFunction, 100);
expect(window.setInterval).toHaveBeenCalledWith(fakeFunction, jasmine.any(Number));
});
});
describe("unmounting", function(){
var subject, fakeFunction;
beforeEach(function(){
fakeFunction = function(){};
subject.setInterval(fakeFunction, 100);
});
React.unmountComponentAtNode(subject.getDOMNode().parentNode);
expect(window.clearInterval).toHaveBeenCalledWith(444);
});
});
}); };
Mixins 45
Learning React.js
If you look at the specs for the shared behavior you will notice they are similar in nature to
the specs for the faux component, but they are slightly more complex. In the “faux” example,
we can do this in the unmounting spec:
This extra complexity is due to fact that the Since2014 code will be calling setInterval in
addition the to calls to setInterval in the shared behavior spec, so we have to be able to
distinguish between them. Otherwise our shared behavior spec might not be testing the
mixin correctly. This means that a “shared behavior” spec will have more noise and
complexity than a comparable “faux spec”. This complexity can be worth it in certain cases: -
If you mixin requires the React component to have certain functions/behavior defined in the
component, the shared behavior spec can validate that the component has those
functions/behavior which the mixin needs (i.e. testing it conforms to the mixin’s interface). - If
a mixin provides behavior to a component that might get easily overridden or messed up by
the component, a shared behavior spec can be a way to assert that doesn’t happen.
With the three available options to test a mixin (direct, faux, and shared behavior), each one
comes with it’s own pros and cons. When testing a mixin, don’t feel afraid to try one option
and switch if it isn’t working out. And it’s possible that a combination of different solutions
covering different parts of the mixin might be the best approach!
Mixins 46
Learning React.js
Dom Manipulation
Chapter 8. DOM Manipulation For the most part, React’s virtual DOM is sufficient to create
the user experience you want without having to work directly with the actual underlying DOM
at all. By composing components together you can weave complex interactions together into
a cohesive whole for the user.
However, in some cases there is no avoiding working with the underlying DOM to
accomplish what you need. The most common use cases for this are when you need to
incorporate a third-party library that does not use React, or when you need to perform an
operation that React does not natively support.
To facilitate this, React provides a system for working with DOM nodes that are being
managed by React. They are only accessible during certain parts of the component lifecycle,
but using them gives you the power you need to handle these use cases.
Accessing Managed DOM Nodes To access DOM nodes managed by React, you must first
be able to access the components responsible for managing them. Adding a ref attribute to
child components lets you do this.
Once we have accessed the child component in question, we can invoke that child’s
getDOMNode() method to access its underlying DOM node. However, we cannot do this in
the render method, because the underlying DOM nodes may not be up-to-date (or even
created yet!) until render completes and React performs its updates.
As such, you cannot invoke the getDOMNode() method until the component has been
“mounted” - at which point the componentDidMount handler will run.
Dom Manipulation 47
Learning React.js
},
},
// Now we can persist the HTML content the user has entered!
} }); The above example creates a div with contentEditable enabled, allowing the user to
enter rich text into it.
Although React does not natively provide a way to access a component’s raw HTML
contents, the keyDown handler can accesses that div’s underlying DOM node, which in turn
can access the raw HTML. From there, you can save a copy of what the user has entered so
far, compute a word count to display, and so on.
Incorporating Non-React Libraries There are many useful JavaScript libraries that were not
built with React in mind. Some do not need DOM access (for example, date and time
manipulation libraries), but for those that do, keeping their states synchronized with React is
critical for successful integration.
Suppose you want to use an autocomplete library which includes the following example
code:
},
Dom Manipulation 48
Learning React.js
getDefaultProps: function() { return { data: [ "San Francisco", "St. Louis", "Amsterdam", "Los
Angeles" ] }; },
handleSelect: function(city) { alert("You have selected the city of " + city); } }); To finish
wrapping this library in React, add a componentDidMount handler which connects the two
implementations via the underlying DOM node of the autocompleteTarget child component.
},
getDefaultProps: function() { return { data: [ "San Francisco", "St. Louis", "Amsterdam", "Los
Angeles" ] }; },
Summary When using the virtual DOM alone is not sufficient, the ref attribute allows you to
access specific elements and modify their underlying DOM nodes using getDOMNode once
componentDidMount has run.
This allows you to make use of functionality that React does not natively support, or to
incorporate third-party libraries that were not designed to interoperate with React.
Next, it’s time to look at how you can write tests to ensure your React components are
working as expected.
Dom Manipulation 49
Learning React.js
Redux
Three Principles
Action
Actions are payloads of information that send data from your application to your store. They
are the only source of information for the store. You send them to the store using
store.dispatch().
Reducer
Actions describe the fact that something happened, but don’t specify how the application’s
state changes in response. This is the job of a reducer.
Store
The Store is the object that brings them together. The store has the following responsibilities:
Holds application state; Allows access to state via getState(); Allows state to be updated via
dispatch(action); Registers listeners via subscribe(listener).
Redux 50