Basic React Quick Reference Examples

With Enzyme & Chai Tests

Quick reference for React UI Component development & testing. Useful for copy & pasting new components to get started. Also goes over basic patterns in React to get most stuff done, all on one place.

Components

We name components using CamelCase. The extension is .jsx. Our example will be MyComponent.jsx.

Every React component starts the same way. Copy and paste the following into a new file.

Component Starter

// MyComponent.jsx
import React, { PropTypes } from 'react';
export default class MyComponent extends React.Component {
  static propTypes = {};
  constructor(props, context) {
super(props, context);
this.state = {}
}
  render() {
return (
<div className="my-component"></div>
)
}
}

Test Starter

Corresponding test files have the same name as the component except the extension is .test.js instead of .jsx

// MyComponent.test.js
import React from 'react';
import { mount, shallow } from 'enzyme';
import { expect } from 'chai';
import MyComponent from './MyComponent';
describe('<MyComponent />', () => {
  it('Renders the proper class', () => {
const component = shallow(<MyComponent />);
expect(component.find('.my-component').length).to.equal(1);
});
});

Passing in Props

In React, if a component is a function, props are the signature. Props are how components communicate with each other. They can be any structure in javascript. String, Arrays, Objects, Functions, etc. The analogy in HTML is an attribute and they can include normal html attributes.

The only gotchas are className instead of class and labelFor instead of for as they are both reserved words in javascript.

// Usage
<Image src="image.jpg" className="photo" />
// Component Definition
export default class Image extends React.Component {
  constructor(props, context) {
super(props, context);
}
  render() {
const cdnPath = '//s3.amazonws.com/bucket/';
const { src, …otherProps } = this.props;
const cdnSrc = cdnPath + src;
return <img src={cdnSrc} {…otherProps} />;
}
}

In the above example we are creating a Image component that adds a path to a CDN in the render function. The value is placed within the JSX using single brackets. {}

Props are just an object, so they can be defined and added all at once.

We use the splat {…otherProps} to indicate any additional stuff we’d like to pass thru to the <img> tag. In the above example className is part of otherProps.

Browser Events and State

In React events are declared in the JSX, with onEventName. The handler is a function either passed in as a prop from a parent or declared in the component class itself.

Passing in Event handlers from a Parent Component

// Component Definition
export default class Button extends React.Component {
  constructor(props, context) {
super(props, context);
}
  render() {
return (
<a className="button"
onClick={this.props.onClick}>{this.props.label}</a>
)
}
}
// Usage
<Button onClick={this.props.clickHandler} />

// Parent Component Definition
import Button from '../Button/Button';
export default class ButtonParent extends React.Component {
  constructor(props, context) {
super(props, context);
}
  clickHandler() {
this.setState({numClicks: this.state.numClicks + 1});
}
  render() {
return (
<p>Clicked {this.state.numClicks} times</p>
<Button onClick={this.clickHandler} label="Click Me!" />
)
}
}

In the above example, we import the Button component for use in the parent’s render function. Button gets a prop called onClick (but can be named anything). That props’s value is the clickHandler function in the ButtonParent class. In this way we allow for dumb or “pure” components like Button to not have to define their own click handlers or labels, so they can be used for different purposes and still deliver consistent results.

This is the preferred way to handle events and state in React. The top most parent passes in all the functions as props that the children call.

Handling Events on the Component Itself

But sometimes you just need to call a function on the component itself on an event. For this there’s one more step to get it to work.

// Component Definition
export default class Accordion extends React.Component {
  constructor(props, context) {
super(props, context);
this.state = { collapsed: this.props.collapsed };
this.togglePanel = this.togglePanel.bind(this);
}
  togglePanel(event) {
this.setState({
collapsed: !this.state.collapsed
});
}
render() {
const label = (this.state.collapsed ? 'Open' : 'Close');
const panelClasses = 'panel '+ (this.state.collapsed ? 'panel- collapsed');
return (
<a className="accordion"
onClick={this.togglePanel} />{label}</a>
<div className={panelClasses}></div>
)
}
// Usage
<Accordion collapsed={false} />

In this example Accordion handles it’s own clicking with this.togglePanel(). We setState and reverse the last collapsed state from true to false. state.collapsed is used in the render function to calculate the label and the classes every time setState re-runs the render.

There is one gotcha. Because of how scoping is different in ES6 when translated to ES5 using Babel. If you don’t bind the event handling function to the right this you’ll get an error along the lines of

Can't call setState of undefined.

You’ll also notice you can pass in the event as the first argument and can call event.target to get the HTML node that was clicked.

Communicating with the Server

Last thing we want to is communicate with the server. When a component loads it may require data on the fly. The component can fetch this data itself in the componentWillMount function. Which is analogous to the $(document).ready() function in jQuery.

export default class Search extends React.Component {
  constructor(props, context) {
super(props, context);
this.state = {
results: []
}
this.fetchResults = this.fetchResults.bind(this);
}
  fetchResults(event) {
const http = new XMLHttpRequest({ responseType: "json" });
http.open("GET", "/search?query=" + event.target.value, true);
http.onload = () => {
const resultsArray = JSON.parse(http.responseText);
this.setState({results: resultsArray});
};
http.send();
}
  render() {
return (
<div className="search">
<input type="text"
className="search__input"
onKeyPress={this.fetchResults} />
</div>
)
}
}

In the above example we want to make a call to the server every time the user presses a key in an input. fetchResults uses a plain ol XMLHttpRequest to quickly get the job done, tho React will work with anything, fetch() $.ajax() or more involved stores like Redux.

Mocking XMLHttpRequest with Sinon

We don’t have to actually use a server when testing requests. That’s too slow. Mocking it out is much easier. We’ve been using Sinon to recreate the request in our tests.

import React from 'react';
import { mount, shallow } from 'enzyme';
import { expect } from 'chai';
import sinon from 'sinon';
import Search from './Search';
describe('<Search />', () => {
describe('onKeyPress', () => {
    var xhr, requests = [];
    before(() => {
xhr = sinon.useFakeXMLHttpRequest();
xhr.onCreate = (req) => { requests.push(req) };
});
    after(() => { xhr.restore() });
    it('fetches to the Server', () => {
requests = [];
const component = shallow(<Search />);
component.find('.search__input')
.simulate('keyPress', {target: {value: 'test'}});
expect(requests.length).to.equal(1);
expect(requests[0].url).to.equal('/search?query=test');
});
});
});

In the above example we’re setting up the mock sinon.useFakeXMLHttpRequest() in a before block. Which work the same as Minitest or rSpec. before runs once for the describe beforeEach runs before every it. Same with after. And in this case we’re cancelling the mock to clean up after ourselves.

The way that it works is, every time our component tries to call XMLHttpRequest it is intercepted by our mock in the xhr.onCreate function which adds the request to an array. We can then use the request in our expect.

In this case we test if a request was created so the array length = 1. And we inspect that first request url to make sure it includes the input from our component. In this case “test.”

Conclusion

This should serve as a reference for the most common basic patterns in React. Props and state, events and server requests, each with a way to test. Tests run extremely quickly, so more tests will not be expected to make the suite noticeably slower. With React, enzyme, Chai and Sinon, tests run at about 1 per 2 milliseconds. So 500 tests per second! This is game changing.