React Bits PDF
React Bits PDF
of Contents
Introduction 1.1
Design Patterns and Techniques 1.2
Conditional in JSX 1.2.1
Async Nature Of setState() 1.2.2
Dependency Injection 1.2.3
Context Wrapper 1.2.4
Event Handlers 1.2.5
Flux Pattern 1.2.6
One Way Data Flow 1.2.7
Presentational vs Container 1.2.8
Third Party Integration 1.2.9
Passing Function To setState() 1.2.10
Decorators 1.2.11
Feature Flags 1.2.12
Component Switch 1.2.13
Reaching Into A Component 1.2.14
List Components 1.2.15
Format Text via Component 1.2.16
Share Tracking Logic 1.2.17
Anti-Patterns 1.3
Introduction 1.3.1
Props In Initial State 1.3.2
findDOMNode() 1.3.3
Mixins 1.3.4
setState() in componentWillMount() 1.3.5
Mutating State 1.3.6
Using Indexes as Key 1.3.7
1
Spreading Props on DOM elements 1.3.8
Handling UX Variations 1.4
Introduction 1.4.1
Composing UX Variations 1.4.2
Toggle UI Elements 1.4.3
HOC for Feature Toggles 1.4.4
HOC props proxy 1.4.5
Wrapper Components 1.4.6
Display Order Variations 1.4.7
Perf Tips 1.5
Introduction 1.5.1
shouldComponentUpdate() check 1.5.2
Using Pure Components 1.5.3
Using reselect 1.5.4
Styling 1.6
Introduction 1.6.1
Stateless UI Components 1.6.2
Styles Module 1.6.3
Style Functions 1.6.4
npm Modules 1.6.5
Base Component 1.6.6
Layout Component 1.6.7
Typography Component 1.6.8
HOC for Styling 1.6.9
Gotchas 1.7
Introduction 1.7.1
Pure render checks 1.7.2
Synthetic Events 1.7.3
Related Links 1.8
2
3
Introduction
React Bits
A compilation of React Patterns, techniques, tips and tricks.
Translations by community:
4
Introduction
setState() in componentWillMount()
Mutating State
Using Indexes as Key
Spreading Props on DOM elements
Handling UX Variations
Introduction
Composing UX Variations
Toggle UI Elements
HOC for Feature Toggles
HOC props proxy
Wrapper Components
Display Order Variations
Perf Tips
Introduction
shouldComponentUpdate() check
Using Pure Components
Using reselect
Styling
Introduction
Stateless UI Components
Styles Module
Style Functions
NPM Modules
Base Component
Layout Component
Typography Component
HOC for Styling
Gotchas
Introduction
Pure render checks
Synthetic Events
Related Links
5
Conditional in JSX
Conditionals in JSX
Instead of
6
Conditional in JSX
There are some libraries that solve this problem (JSX-Control Statements), but
rather than introduce another dependency use an IIFE and return values by using
if-else statement inside
7
Conditional in JSX
Related links:
https://engineering.musefind.com/our-best-practices-for-writing-react-
components-dec3eb5c3fc8
Conditional rendering
8
Conditional in JSX
9
Async Nature Of setState()
Gist:
React batches updates and flushes it put once per frame (perf optimization)
However, in some cases React has no control over batching, hence updates are
made synchronously eg. eventListeners, Ajax, setTimeout and similar Web APIs
Main Idea
setState() does not immediately mutate this.state but creates a pending state
transition. Accessing this.state after calling this method can potentially return the
existing value. There is no guarantee of synchronous operation of calls to setState
and calls may be batched for performance gains.
Run the below code and you will make the following observations:
You can see that in every situation (addEventListener, setTimeout or AJAX call)
the state before and the state after are different. And that render was called
immediately after triggering the setState method. But why is that? Well, it turns out
React does not understand and thus cannot control code that doesn't live inside
the library. Timeouts or AJAX calls for example, are developer authored code that
executes outside of the context of React.
So why does React synchronously update the state in these cases? Well,
because it's trying to be as defensive as possible. Not being in control means it's
not able to do any performance optimisations so it's better to update the state on
spot and make sure the code that follows has access to the latest information
available.
10
Async Nature Of setState()
dollars: 10
};
this._saveButtonRef = (btn => { this._btnRef = btn });
[
'_onTimeoutHandler',
'_onMouseLeaveHandler',
'_onClickHandler',
'_onAjaxCallback',
].forEach(propToBind => {
this[propToBind] = this[propToBind].bind(this);
});
}
componentDidMount() {
// Add custom event via `addEventListener`
//
// The list of supported React events does include `mouselea
ve`
// via `onMouseLeave` prop
//
// However, we are not adding the event the `React way` - th
is will have
// effects on how state mutates
//
// Check the list here - https://reactjs.org/docs/events.html
this._btnRef.addEventListener('mouseleave', this._onMouseLea
veHandler);
// Add JS timeout
//
// Again,outside React `world` - this will also have effects
on how state
// mutates
setTimeout(this._onTimeoutHandler, 10000);
11
Async Nature Of setState()
render() {
console.log('State in render: ' + JSON.stringify(this.state)
);
return (
<button
ref={this._saveButtonRef}
onClick={this._onClickHandler}>
'Click me'
</button>
);
}
_onClickHandler() {
console.log('State before (_onClickHandler): ' + JSON.string
ify(this.state));
this.setState({
dollars: this.state.dollars + 10
});
console.log('State after (_onClickHandler): ' + JSON.stringi
fy(this.state));
}
_onMouseLeaveHandler() {
console.log('State before (mouseleave): ' + JSON.stringify(t
his.state));
this.setState({
dollars: this.state.dollars + 20
});
console.log('State after (mouseleave): ' + JSON.stringify(th
is.state));
}
_onTimeoutHandler() {
console.log('State before (timeout): ' + JSON.stringify(this
.state));
this.setState({
dollars: this.state.dollars + 30
});
12
Async Nature Of setState()
_onAjaxCallback(response) {
if (response.status !== 200) {
console.log('Error in AJAX call: ' + response.statusText);
return;
}
console.log('State before (AJAX call): ' + JSON.stringify(th
is.state));
this.setState({
dollars: this.state.dollars + 40
});
console.log('State after (AJAX call): ' + JSON.stringify(this
.state));
}
};
// Render to DOM
ReactDOM.render(
<TestComponent />,
document.getElementById('app')
);
Possible solution?
We're used to calling setState with one parameter only, but actually, the method's
signature support two. The second argument that you can pass in is a callback
function that will always be executed after the state has been updated (whether
it's inside React's known context or outside of it).
13
Async Nature Of setState()
14
Async Nature Of setState()
What's actually sync or async are the effects of calling setState in a React
application - the reconciliation algorithm, doing the VDOM comparisons and
calling render to update the real DOM.
Related links:
https://medium.com/@wereHamster/beware-react-setstate-is-asynchronous-
ce87ef1a9cf3#.jhdhncws3
https://www.bennadel.com/blog/2893-setstate-state-mutation-operation-may-
be-synchronous-in-reactjs.htm
15
Dependency Injection
Dependency Injection
In React the need of dependency injection is easily visible. Let's consider the
following application tree:
// Title.jsx
export default function Title(props) {
return <h1>{ props.title }</h1>;
}
// Header.jsx
import Title from './Title.jsx';
export default function Header() {
return (
<header>
<Title />
</header>
);
}
// App.jsx
import Header from './Header.jsx';
class App extends React.Component {
constructor(props) {
super(props);
this.state = { title: 'React Dependency Injection' };
}
render() {
return <Header />;
}
}
The string "React Dependency Injection" should somehow reach the Title
component. The direct way of doing this is to pass it from App to Header and then
Header to pass it to Title. However, this may work for these three components but
16
Dependency Injection
what happens if there are multiple properties and deeper nesting. Lots of
components will have to mention properties that they are not interested in. It is
clear that most React components receive their dependencies via props but the
question is how these dependencies reach that point.
// inject.jsx
var title = 'React Dependency Injection';
export default function inject(Component) {
return class Injector extends React.Component {
render() {
return (
<Component
{...this.state}
{...this.props}
title={ title }
/>
)
}
};
}
// Title.jsx
export default function Title(props) {
return <h1>{ props.title }</h1>;
}
17
Dependency Injection
// Header.jsx
import inject from './inject.jsx';
import Title from './Title.jsx';
App.childContextTypes = {
title: PropTypes.string
};
18
Dependency Injection
Related links:
What is Dependency Injection?
The Basics of Dependency Injection
Dependency injection in JavaScript
DI In React
19
Context Wrapper
Context Wrapper
It is a good practice that our context is not just a plain object but it has an interface
that allows us to store and retrieve data. For example:
// dependencies.js
export default {
data: {},
get(key) {
return this.data[key];
},
register(key, value) {
this.data[key] = value;
}
}
Then, if we go back to our example, the very top App component may look like
that:
App.childContextTypes = {
data: PropTypes.object,
get: PropTypes.func,
register: PropTypes.func
};
20
Context Wrapper
And our Title component gets it's data through the context:
// Title.jsx
export default class Title extends React.Component {
render() {
return <h1>{ this.context.get('title') }</h1>
}
}
Title.contextTypes = {
data: PropTypes.object,
get: PropTypes.func,
register: PropTypes.func
};
Ideally we don't want to specify the contextTypes every time when we need an
access to the context. This detail may be wrapped in a higher-order component.
And even more, we may write an utility function that is more descriptive and helps
us declare the exact wiring. ie. instead of accessing the context directly with
this.context.get('title') we ask the higher-order component to get what we need
and to pass it as a prop to our component. For example:
// Title.jsx
import wire from './wire';
function Title(props) {
return <h1>{ props.title }</h1>;
}
The wire function accepts first a React component, then an array with all the
needed dependencies (which are registered already) and then a function which I
like to call mapper. It receives what's stored in the context as a raw data and
returns an object which is the actual React props for our component (Title). In this
example we just pass what we get - a title string variable. However, in a real app
21
Context Wrapper
this could be a collection of data stores, configuration or something else. So, it's
nice that we pass exactly what we need and don't pollute the components with
data that they don't need.
Inject is a higher-order component that gets access to the context and retrieves all
the items listed under dependencies array. The mapper is a function receiving the
context data and transforms it to props for our component.
Non-context alternative
Use a singleton to register/fetch all dependencies
22
Context Wrapper
We'll store the dependencies in dependencies global variable (it's global for our
module, not at an application level).
We then export two functions register and fetch that write and read entries.
It looks a little bit like implementing setter and getter against a simple JavaScript
object.
Then we have the wire function that accepts our React component and returns a
higher-order component.
23
Context Wrapper
In the constructor of that component we are resolving the dependencies and later
while rendering the original component we pass them as props.
We follow the same pattern where we describe what we need (deps argument)
and extract the needed props with a mapper function.
Having the di.jsx helper we are again able to register our dependencies at the
entry point of our application (app.jsx) and inject them wherever (Title.jsx) we
need.
// app.jsx
import Header from './Header.jsx';
import { register } from './di.jsx';
// Header.jsx
import Title from './Title.jsx';
24
Context Wrapper
// Title.jsx
import { wire } from './di.jsx';
If we look at the Title.jsx file we'll see that the actual component and the
wiring may live in different files. That way the component and the mapper function
become easily unit testable.
25
Event Handlers
Event Handlers
Binding event handlers in the constructor.
Most of the times we handle DOM events in the component that contains the
elements dispatching the events. Like in the example below, we have a click
handler and we want to run a function or method of the same component:
The problem is that as it is the code doesn't keep the scope. So, if we have to use
this inside _handleButtonClick we'll get an error.
26
Event Handlers
However, this means that the bind function is called again and again because we
may render the button many times. A better approach would be to create the
bindings in the constructor of the component:
27
Event Handlers
The other alternative is to use arrow functions for the onClick prop function
assignment. Arrow functions don't affect the context at invocation time ( this
value from the surrounding scope is used).
Facebook by the way recommend the same technique while dealing with functions
that need the context of the same component. The binding in the constructor may
be also useful if we pass callbacks down the tree.
A short hand example using arrow functions and avoid having to use the
constructor:
28
Event Handlers
render() {
return (
<button onClick={ this._handleButtonClick }>
click me
</button>
);
}
_handleButtonClick = () => {
console.log(`Button is clicked inside ${ this.state.name }`)
;
}
}
29
Flux Pattern
We expect the store to have an update method(), so let's modify register to expect
it.
function register(store) {
if (!store || !store.update || typeof store.update !== 'functi
on') {
throw new Error('You should provide a store that has an upda
te method');
} else {
this._stores.push({store: store});
}
}
30
Flux Pattern
return {
_stores: [],
register: function (store) {
if (!store || !store.update) {
throw new Error('You should provide a store that has an
`update` method.');
} else {
var consumers = [];
var change = function () {
consumers.forEach(function (l) {
l(store);
});
};
var subscribe = function (consumer, noInit) {
consumers.push(consumer);
!noInit ? consumer(store) : null;
};
module.exports = {
create: function () {
var dispatcher = Dispatcher();
return {
createAction: function (type) {
if (!type) {
31
Flux Pattern
Related links:
https://github.com/krasimir/react-in-patterns/tree/master/patterns/flux
32
One Way Data Flow
var Store = {
_handlers: [],
_flag: '',
onChange: function (handler) {
this._handlers.push(handler);
},
set: function (value) {
this._flag = value;
this._handlers.forEach(handler => handler())
},
get: function () {
return this._flag;
}
};
Then we will hook our main App component and we'll re-render it every time when
the Store changes its value:
33
One Way Data Flow
render() {
return (
<div>
<Switcher
value={ Store.get() }
onChange={ Store.set.bind(Store) }/>
</div>
);
}
}
Because of this change the Switcher becomes really simple. We don't need the
internal state:
34
One Way Data Flow
render() {
return (
<button onClick={ this._onButtonClick }>
{ this.props.value ? 'lights on' : 'lights off' }
</button>
);
}
}
The benefit that comes with this pattern is that our components become dummy
representation of the Store's data. It's really easy to think about the React
components as views (renderers). We write our application in a declarative way
and deal with the complexity in only one place.
Related links:
https://www.startuprocket.com/articles/evolution-toward-one-way-data-flow-a-
quick-introduction-to-redux
35
Presentational vs Container
render() {
var time = this._formatTime(this.state.time);
return (
<h1>{ time.hours } : { time.minutes } : { time.seconds }</
h1>
);
}
componentDidMount() {
this._interval = setInterval(this._update, 1000);
}
componentWillUnmount() {
clearInterval(this._interval);
}
_formatTime(time) {
var [ hours, minutes, seconds ] = [
time.getHours(),
time.getMinutes(),
time.getSeconds()
].map(num => num < 10 ? '0' + num : num);
36
Presentational vs Container
_updateTime() {
this.setState({time: new Date(this.state.time.getTime() + 10
00)});
}
}
Solution
Let's split the component into two parts - container and presentation.
Container Component
Containers know about data, it's shape and where it comes from. They know
details about how the things work or the so called business logic. They receive
information and format it so it is easy to use by the presentational component.
Very often we use higher-order components to create containers. Their render
method contains only the presentational component.
37
Presentational vs Container
// Clock/index.js
import Clock from './Clock.jsx'; // <-- that's the presentationa
l component
render() {
return <Clock { ...this._extract(this.state.time) }/>;
}
componentDidMount() {
this._interval = setInterval(this._update, 1000);
}
componentWillUnmount() {
clearInterval(this._interval);
}
_extract(time) {
return {
hours: time.getHours(),
minutes: time.getMinutes(),
seconds: time.getSeconds()
};
}
_updateTime() {
this.setState({time: new Date(this.state.time.getTime() + 10
00)});
}
};
Presentational component
38
Presentational vs Container
Presentational components are concerned with how the things look. They have
the additional markup needed for making the page pretty. Such components are
not bound to anything and have no dependencies. Very often implemented as a
stateless functional components they don't have internal state.
// Clock/Clock.jsx
export default function Clock(props) {
var [ hours, minutes, seconds ] = [
props.hours,
props.minutes,
props.seconds
].map(num => num < 10 ? '0' + num : num);
The nice things about containers is that they encapsulate logic and may inject
data into different renderers. Very often a file that exports a container is not
sending out a class directly but a function. For example, instead of using
39
Presentational vs Container
Using this technique our container is really flexible in rendering its result. It will be
really helpful if we want to switch from digital to analog clock representation.
Related links:
https://medium.com/@dan_abramov/smart-and-dumb-components-
7ca2f9a7c7d0#.mbglcakmp
https://github.com/krasimir/react-in-
patterns/tree/master/patterns/presentational-and-container
https://medium.com/@learnreact/container-components-c0e67432e005
40
Third Party Integration
In this example we'll see how to mix React and jQuery's UI plugin. We pick tag-it
jQuery plugin for the example. It transforms an unordered list to input field for
managing tags:
<ul>
<li>JavaScript</li>
<li>CSS</li>
</ul>
To make it work we have to include jQuery, jQuery UI and the tag-it plugin code. It
works like that:
The very first thing that we have to do is to force a single-render of the Tags
component. That's because when React adds the elements in the actual DOM we
want to pass the control of them to jQuery. If we skip this both React and jQuery
will work on same DOM elements without knowing for each other. To achieve a
single-render we have to use the lifecycle method shouldComponentUpdate
Let's say that we want to programmatically add a new tag to the already running
tag-it field. Such action will be triggered by the React component and needs to
use the jQuery API. We have to find a way to communicate data to Tags
component but still keep the single-render approach. To illustrate the whole
process we will add an input field to the App class and a button which if clicked
will pass a string to Tags component.
41
Third Party Integration
this._addNewTag = this._addNewTag.bind(this);
this.state = {
tags: ['JavaScript', 'CSS'],
newTag: null
};
}
_addNewTag() {
this.setState({newTag: this.refs.field.value});
}
render() {
return (
<div>
<p>Add new tag:</p>
<div>
<input type='text' ref='field'/>
<button onClick={ this._addNewTag }>Add</button>
</div>
<Tags tags={ this.state.tags } newTag={ this.state.newTa
g }/>
</div>
);
}
}
We use the internal state as a data storage for the value of the newly added field.
Every time when we click the button we update the state and trigger re-rendering
of Tags component. However, because of shouldComponentUpdate we update
nothing. The only one change is that we get a value of the newTag prop which
may be captured via another lifecycle method - componentWillReceiveProps
42
Third Party Integration
shouldComponentUpdate() {
return false;
}
componentWillReceiveProps(newProps) {
this.list.tagit('createTag', newProps.newTag);
}
render() {
return (
<ul ref='list'>
{ this.props.tags.map((tag, i) => <li key={ i }>{ tag }
</li>) }
</ul>
);
}
}
Related links:
https://github.com/krasimir/react-in-patterns/tree/master/patterns/third-party
43
Passing Function To setState()
Problem
Solution
Variations
// Passing object
this.setState({ expanded: !this.state.expanded });
// Passing function
this.setState(prevState => ({ expanded: !prevState.expanded }));
Related links:
44
Passing Function To setState()
setState() Gate
Do I need to use setState(function) overload in this case?
Functional setState is the future of React
45
Decorators
Decorators
Decorators (supported by Babel, in Stage 2 proposal as of 03/17)
If you’re using something like mobx, you can decorate your class components —
which is the same as passing the component into a function. Decorators are
flexible and readable way of modifying component functionality.
Non-decorators approach
With decorators
@observer
export default class ProfileContainer extends Component {
// Component code
}
Article:
Enhancing React components with Decorators
Related:
Decorators != higher ordered components
React Decorator example - Module
What is the use of Connect(decorator in react-redux)
Decorators with React Components
Exploring ES7 decorators
Understanding Decorators
46
Decorators
47
Feature Flags
Feature Flags
Enabling Feature flags in React using Redux
// createFeatureFlaggedContainer.js
import React from 'react';
import { connect } from 'react-redux';
import { isFeatureEnabled } from './reducers'
if (Component) {
return <Component {...props} />;
}
48
Feature Flags
// EnabledFeature.js
import { connect } from 'react-redux';
import { isFeatureEnabled } from './reducers'
return null;
}
// featureEnabled.js
import createFeatureFlaggedContainer from './createFeatureFlagge
dContainer'
49
Feature Flags
// features.js
// This is quite simple reducer, containing only an array of fea
tures.
// You can attach this data to a `currentUser` or similar reduce
r.
50
Feature Flags
// reducers.js
// This is your main reducer.js file
import { combineReducers } from 'redux';
Related links:
Feature flags in React
Gist
51
Component Switch
const PAGES = {
home: HomePage,
about: AboutPage,
user: UserPage
};
// The keys of the PAGES object can be used in the prop types to
catch dev-time errors.
Page.propTypes = {
page: PropTypes.oneOf(Object.keys(PAGES)).isRequired
};
Related links:
https://hackernoon.com/10-react-mini-patterns-c1da92f068c5
52
Reaching Into A Component
Child Component
An input component with a focus() method that focuses the HTML element
render() {
return (
<input
ref={el=> { this.el = el; }}
/>
);
}
}
Parent Component
In the parent component, we can get a reference to the Input component and call
its focus() method.
53
Reaching Into A Component
render() {
return (
<div>
<label>User name:</label>
<Input
ref={comp => { this.InputComponent = comp; }}
/>
</div>
)
}
}
Reference:
https://hackernoon.com/10-react-mini-patterns-c1da92f068c5
54
List Components
Lists Components
Lists and other things that are almost components
Instead of making a separate component for lists I can then generate the results
like:
return (
<ul>
{props.listItems.map(renderSearchSuggestion)}
</ul>
);
};
If things get more complex or you want to use this component elsewhere, you
should be able to copy/paste the code out into a new component. Don’t
prematurely componentize.
Related links:
https://hackernoon.com/10-react-mini-patterns-c1da92f068c5
55
Format Text via Component
With Component
Render function is lot cleaner to comprehend as it is just simple component
composition.
Price.propTypes = {
className: PropTypes.string,
children: PropTypes.number,
showDecimals: PropTypes.bool,
showSymbol: PropTypes.bool
};
Price.defaultProps = {
children: 0,
showDecimals: true,
showSymbol: true,
};
56
Format Text via Component
return (
<div>
<p>One lamb is <Price className="expensive">{lambPrice}</P
rice></p>
<p>One jet is <Price showDecimals={false}>{jetPrice}</Price
></p>
<p>Those gumboots will set ya back
<Price
showDecimals={false}
showSymbol={false}>
{bootPrice}
</Price>
bucks.
</p>
</div>
);
};
Without Component
Less code: But render looks less clean. (Debatable, yeah I understand)
57
Format Text via Component
return num.toLocaleString('en', {
style: showSymbol ? 'currency' : undefined,
currency: showSymbol ? 'USD' : undefined,
maximumFractionDigits: showDecimals ? 2 : 0
});
}
return (
<div>
<p>One lamb is <span className="expensive">{numberToPrice(
lambPrice)}</span></p>
<p>One jet is {numberToPrice(jetPrice, { showDecimals: fal
se })}</p>
<p>Those gumboots will set ya back
{numberToPrice(bootPrice, { showDecimals: false, showSym
bol: false })}
bucks.</p>
</div>
);
};
Reference:
10 React Mini Patterns
58
Share Tracking Logic
59
Share Tracking Logic
// HOC
const pageLoadTracking = (ComposedComponent) => class HOC extends
Component {
componentDidMount() {
tracker.trackPageLoad(this.props.trackingData);
}
componentDidUpdate() {
tracker.trackPageLoad(this.props.trackingData);
}
render() {
return <ComposedComponent {...this.props} />
}
};
// Usage
import LoginComponent from "./login";
60
Introduction
Anti-patterns
Familiarizing ourselves with common anti-patterns will help us understand how
React works and describe useful forms of refactoring our code.
61
Props In Initial State
The danger is that if the props on the component are changed without the
component being ‘refreshed’, the new prop value will never be displayed because
the constructor function (or getInitialState) will never update the current state of
the component. The initialization of state from props only runs when the
component is first created.
Bad
render() {
return <div>{this.state.inputVal && <AnotherComponent/>}</div
>
}
}
Good
62
Props In Initial State
render() {
return <div>{this.props.inputValue && <AnotherComponent/>}</
div>
}
}
Related links:
React Anti-Patterns: Props in Initial State
Why is passing the component initial state a prop an anti-pattern?
63
findDOMNode()
Note: React also supports using a string (instead of a callback) as a ref prop on
any component, although this approach is mostly legacy at this point.
findDOMNode(this)
Before:
render() {
return <div />
}
}
After
render() {
return <div ref={node => this.node = node}/>
}
}
findDOMNode(stringDOMRef)
64
findDOMNode()
Before
render() {
return (
<div>
<div ref='something'/>
</div>
)
}
}
After
render() {
return (
<div>
<div ref={node => this.something = node}/>
</div>
)
}
}
findDOMNode(childComponentStringRef)
Before:
65
findDOMNode()
render() {
return (
<div>
Hello,
<Field ref='myInput'/>
</div>
)
}
}
After
66
findDOMNode()
render() {
return (
<div>
Hello,
<Field inputRef={node => this.inputNode = node}/>
</div>
)
}
}
Related links:
ESLint Rule proposal: warn against using findDOMNode()
Refs and the DOM
67
Mixins
// With Mixin
var WithLink = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function () {
return {message: 'Hello!'};
},
render: function () {
return <input type="text" valueLink={this.linkState('message
')}/>;
}
});
Detailed Example
// With Mixin
var CarDataMixin = {
componentDidMount: {
// fetch car data and
// call this.setState({carData: fetchedData}),
// once data has been (asynchronously) fetched
}
68
Mixins
};
// With HOC
var bindToCarData = function (Component) {
return React.createClass({
componentDidMount: {
// fetch car data and
// call this.setState({carData: fetchedData}),
// once data has been (asynchronously) fetched
},
render: function () {
return <Component carData={ this.state.carData }/>
}
});
};
69
Mixins
Related links:
Mixins are dead - Long live higher ordercomponents
Mixins are considered harmful
Stackoverflow: Using mixins vs components for code reuse
Stackoverflow: Composition instead of mixins in React
70
setState() in componentWillMount()
setState() in componentWillMount()
Avoid async initialization in componentWillMount()
function componentDidMount() {
axios.get(`api/messages`)
.then((result) => {
const messages = result.data
console.log("COMPONENT WILL Mount messages : ", messages);
this.setState({
messages: [...messages.content]
})
})
}
71
Mutating State
Bad
this.state = {
items: ['foo', 'bar']
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// BAD: We mutate state here
this.state.items.push('lorem');
this.setState({
items: this.state.items
});
}
render() {
return (
<div>
{this.state.items.length}
<button onClick={this.handleClick}>+</button>
</div>
)
}
}
72
Mutating State
Good
this.state = {
items: ['foo', 'bar']
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// We update using setState() - concat return new array afte
r appending new item.
this.setState({
items: this.state.items.concat('lorem')
});
}
render() {
return (
<div>
{this.state.items.length}
<button onClick={this.handleClick}>+</button>
</div>
)
}
}
Related links:
React Design Patterns and best practices by Michele Bertoli.
73
Using Indexes as Key
Bad
In this snippet each element's key will be based on ordering, rather than tied to
the data that is being represented. This limits the optimizations that React can do.
Good
Assuming todo.id is unique to this list and stable, React would be able to
reorder elements without needing to reevaluate them as much.
{todos.map((todo) =>
<Todo {...todo}
key={todo.id} />
)}
@Reference:
React docs
Lin Clark's code cartoon
74
Spreading Props on DOM elements
Bad
This will try to add the unknown HTML attribute flag to the DOM element.
Good
By creating props specifically for DOM attribute, we can safely spread.
Note
75
Spreading Props on DOM elements
Related links:
React Design Patterns and best practices by Michele Bertoli.
In React, children are just props: Kent C. Dodds' Tweet
76
Introduction
Components/Containers code must essentially deal with only one chunk of the UI
feature/functionality.
Address container (Only has address related fields), Name container (first
and last name), Phone component, State, City and Zip code container
In Redux
All API related call go into Redux thunks/other async handling sections (redux-
promise, sagas etc)
The thunks are responsible only for the dispatching action on AJAX begin/fail
and complete.
Any routing has to be dealt with the receiving component via a promise.
77
Introduction
Don’t pass any more props than required {...this.props} only if the list is big --
if not pass individual props.
Too much flows of control (If-else variations) inside the component is usually
a red-flag. This most likely means - need to split up the component or create
a separate variation.
Articles
Building React Components for Multiple Brands and Applications
78
Composing UX Variations
If we have a bunch of renderBla() functions within the component which are used
in the main component render()
Example
Login page variations
79
Composing UX Variations
_routeTo() {
// Routing logic here
}
render() {
const {forgotEmailRoute,forgotPwdRoute, showMemberSignupLink
s} = this.props;
return (
<div>
<SignIn
onForgotPasswordRequested={this._routeTo(forgotPwdRout
e)}
onForgotEmailRequested={this._routeTo(forgotEmailRoute
)}>
{this.props.children}
{showMemberSignupLinks && this._renderMemberJoinLinks(
)}
</SignIn>
</div>
);
}
}
80
Composing UX Variations
Related links:
Slides from my talk: Building Multi-tenant UI with React
81
Toggle UI Elements
Toggle UI Elements
Handling minor UX variations in the component by toggling ON/OFF features.
Gotcha:
Easy to overuse this idea by adding props for every variation.
Only add in props for features specific to the current feature that the
component.
Basically, not violate the Single Responsibility Principle.
Example
Show/Hide password feature in Login form
82
Toggle UI Elements
Related links:
Slides from my talk: Building Multi-tenant UI with React
83
HOC for Feature Toggles
// featureToggle.js
const isFeatureOn = function (featureName) {
// return true or false
};
// Usage
import AdsComponent from './Ads'
const Ads = toggleOn('ads', AdsComponent);
84
HOC props proxy
function HOC(WrappedComponent) {
return class Test extends Component {
render() {
const newProps = {
title: 'New Header',
footer: false,
showFeatureX: false,
showFeatureY: true
};
85
Wrapper Components
Wrapper Components
Using Wrappers to handle UX/style variations
For Handling Wrapper <div> ’s and other markup around component, use
composition!
When you create a React component instance, you can include additional React
components or JavaScript expressions between the opening and closing tags.
Parent can read its children by accessing the special this.props.children prop.
FYI - Wrapper component can also be made accept a tag name and then used to
generate the HTML element. However, usually this is not recommended because
you can't add attributes/props to it.
86
Wrapper Components
Related links:
Slides from my talk: Building Multi-tenant UI with React
87
Display Order Variations
return (
<div className="page-content">
{pageItems}
</div>
)
}
}
Related links:
Slides from my talk: Building Multi-tenant UI with React
88
Introduction
Perf Tips
Key Ideas
Articles
Optimizing Performance: Docs
89
shouldComponentUpdate() check
shouldComponentUpdate() check
shouldComponentUpdate check to avoid expensive re-renders
React Components re-render every time their props or state change. So imagine
having to render the entire page every time there in an action. That takes a big
load on the browser. That’s where ShouldComponentUpdate comes in, whenever
React is rendering the view it checks to see if shouldComponentUpdate is
returning false/true. So whenever you have a component that’s static do yourself a
favor and return false. Or if is not static check to see if the props/state has
changed.
Bad
90
shouldComponentUpdate() check
return (
<li
onMouseLeave={props.onMouseLeave}
className={selectedClass}>
<i className="ion-ios-eye"
data-image={props.image}
data-url={props.url}
data-title={props.title}
onClick={props.handlePlanetViewClick}/>
<span
onMouseEnter={props.onMouseEnter}
>
<div className="dot bg-mint"/>
{path}
</span>
</li>
);
};
Good
91
shouldComponentUpdate() check
render() {
const {props} = this;
const selectedClass = props.selected === true ? "selected" :
"";
var path = parseUri(props.url).path;
path = path.length <= 0 ? props.url : "..." + path;
return (
<li
onMouseLeave={props.onMouseLeave}
className={selectedClass}>
<i className="ion-ios-eye"
data-image={props.image}
data-url={props.url}
data-title={props.title}
onClick={props.handlePlanetViewClick}/>
<span
onMouseEnter={props.onMouseEnter}>
<div className="dot bg-mint"/>
{path}
</span>
</li>
);
}
}
Related links:
React Performance optimization
React rendering misconception
92
shouldComponentUpdate() check
93
Using Pure Components
Recompose offers a Higher Order Component called pure for this purpose and
React added React.PureComponent in v15.3.0.
Bad
Good
Better
94
Using Pure Components
Related links:
Recompose
Higher Order Components with Functional Patterns Using Recompose
React: PureComponent
Pure Components
Top 5 Recompose HOCs
95
Using reselect
Using reselect
Use Reselect in Redux connect(mapState) -- to avoid frequent re-render.
Bad
In this above case every time otherData in the state changes both DataContainer
and ResolutionContainer will be rendered even when the resolution in the state
does not change. This is because the doubleRes function will always return a new
resolution object with a new identity. If doubleRes is written with Reselect the
issue goes away: Reselect memoizes the last result of the function and returns it
when called until new arguments are passed to it.
Good
96
Using reselect
Related links:
React
Computing Derived Data: Docs
97
Introduction
Styling in React
Here we look into some ideas around using CSS in JS.
If you are pondering over why to use CSS in JS, I highly recommend this talk by
Vjeux
Articles
Patterns for style composition in React
98
Stateless UI Components
99
Stateless UI Components
fontWeight: 'bold',
textDecoration: 'none',
display: 'inline-block',
margin: 0,
paddingTop: 8,
paddingBottom: 8,
paddingLeft: 16,
paddingRight: 16,
border: 0,
color: 'white',
backgroundColor: 'blue',
WebkitAppearance: 'none',
MozAppearance: 'none'
}
return (
<button {...props} style={sx}/>
)
}
100
Styles Module
Styles module
Generally, hard coding styles values in a component should be avoided. Any
values that are likely to be used across different UI components should be split
into their own module.
// Styles module
export const white = '#fff';
export const black = '#111';
export const blue = '#07c';
const styles = {
bold: 600,
space,
colors
};
Usage
101
Styles Module
// button.jsx
import React from 'react'
import { bold, space, colors } from './styles'
const Button = ({
...props
}) => {
const sx = {
fontFamily: 'inherit',
fontSize: 'inherit',
fontWeight: bold,
textDecoration: 'none',
display: 'inline-block',
margin: 0,
paddingTop: space[1],
paddingBottom: space[1],
paddingLeft: space[2],
paddingRight: space[2],
border: 0,
color: colors.white,
backgroundColor: colors.blue,
WebkitAppearance: 'none',
MozAppearance: 'none'
};
return (
<button {...props} style={sx}/>
)
};
102
Style Functions
Style Functions
Since we’re using JavaScript, we can also employ helper functions for styling
elements.
Example 1
A function to create rgba values of black
const shade = [
darken(0),
darken(1 / 8),
darken(1 / 4),
darken(3 / 8),
darken(1 / 2),
darken(5 / 8),
darken(3 / 4),
darken(7 / 8),
darken(1)
];
// So now,
// shade[4] is 'rgba(0, 0, 0, 0.5)'
Example 2
Creating a scale for margin and padding to help keep visual rhythm consistent
103
Style Functions
];
// Component usage
const Box = () => (
<div>
<Box m={2} p={3}>
A box with 16px margin and 32px padding
</Box>
</div>
);
104
npm Modules
Example
For darkening scales in CSS you can use chroma-js module
const shade = [
darken(0),
darken(1 / 8),
darken(1 / 4)
// More...
];
const blueAlpha = [
alpha(blue)(0),
alpha(blue)(1 / 4),
alpha(blue)(1 / 2),
alpha(blue)(3 / 4),
alpha(blue)(1)
];
105
Base Component
Base Component
106
Base Component
const Button = ({
big,
color = colors.white,
backgroundColor = colors.blue,
...props
}) => {
const sx = {
fontFamily: 'inherit',
fontSize: 'inherit',
fontWeight: bold,
textDecoration: 'none',
display: 'inline-block',
margin: 0,
paddingTop: big ? space[2] : space[1],
paddingBottom: big ? space[2] : space[1],
paddingLeft: space[2],
paddingRight: space[2],
border: 0,
color,
backgroundColor,
WebkitAppearance: 'none',
MozAppearance: 'none'
};
return (
<button {...props} style={sx}/>
)
};
Usage
107
Base Component
108
Layout Component
Layout component
We can extend the idea of Base components to create Layout components.
Example
109
Layout Component
Usage
Related links:
Github: React Layout components
Leveling Up With React: Container Components
Container Components and Stateless Functional Components in React
110
Typography Component
Typography Component
We can extend the idea of Base components to create Typography components
this pattern helps ensure consistency and keep your styling DRY.
Example
111
Typography Component
const Text = ({
tag = 'span',
size = 4,
alt,
center,
bold,
caps,
...props
}) => {
const Tag = tag;
const sx = {
fontFamily: alt ? alternateFont : null,
fontSize: typeScale[size],
fontWeight: bold ? boldFontWeight : null,
textAlign: center ? 'center' : null,
textTransform: caps ? 'uppercase' : null
};
Usage
112
Typography Component
113
HOC for Styling
Example: Carousel
The HOC will have a current slide index and have previous and next methods.
114
HOC for Styling
this.next = () => {
const { index } = this.state;
this.setState({index: index + 1})
}
}
render() {
return (
<Comp
{...this.props}
{...this.state}
previous={this.previous}
next={this.next}/>
)
}
}
return Carousel
};
export default CarouselContainer;
115
HOC for Styling
// UI component
const Carousel = ({ index, ...props }) => {
const length = props.length || props.children.length || 0;
const sx = {
root: {
overflow: 'hidden'
},
inner: {
whiteSpace: 'nowrap',
height: '100%',
transition: 'transform .2s ease-out',
transform: `translateX(${index % length * -100}%)`
},
child: {
display: 'inline-block',
verticalAlign: 'middle',
whiteSpace: 'normal',
outline: '1px solid red',
width: '100%',
height: '100%'
}
};
return (
<div style={sx.root}>
<div style={sx.inner}>
{children}
</div>
</div>
116
HOC for Styling
)
};
// Wrap the component with the functionality from the higher ord
er component
export default CarouselContainer(HeroCarousel)
By keeping the styling separate from the interactive state, any number of carousel
variations can be created from these reusable parts.
Usage
117
HOC for Styling
118
Introduction
Gotchas
React is intuitive for the most part, but there are quite a few stumbling points
which might catch you by surprise. We'll discuss more on them here.
Articles
React Gotchas
119
Pure render checks
Pure render?
Case 1
Bad
You see the options array was passed deep down in the Cell elements. Normally
this would not be an issue. The other Cell elements would not be re-rendered
because they can do the cheap shallow equality check and skip the render
entirely but in this case the options prop was null and the default array was used.
As you should know the array literal is the same as new Array() which creates a
120
Pure render checks
new array instance. This completely destroyed every pure render optimization
inside the Cell elements. In Javascript different instances have different identities
and thus the shallow equality check always produces false and tells React to re-
render the components.
Good
Case 2
Similar issue with using functions in render() as well
BAD
Bad again
121
Pure render checks
render() {
return <MyInput onChange={this.update.bind(this)}/>;
}
}
^^In both cases a new function is created with a new identity. Just like with the
array literal. We need to bind the function early
Good
update(e) {
this.props.update(e.target.value);
}
render() {
return <MyInput onChange={this.update}/>;
}
}
Bad
122
Pure render checks
onClick() {
this.setState({clicked: true})
}
render() {
// Options object created each render if not set
const options = this.props.options || {test: 1};
return <Something
options={options}
// New function created each render
onClick={this.onClick.bind(this)}
// New function & closure created each render
onTouchTap={(event) => this.onClick(event)
/>
}
}
Good
123
Pure render checks
onClick = () => {
this.setState({clicked: true})
};
render() {
// Options object created once
const options = this.props.options || this.options;
return <Something
options={options}
onClick={this.onClick} // Function created once, bound once
Related links:
https://medium.com/@esamatti/react-js-pure-render-performance-anti-
pattern-fb88c101332f
https://github.com/nfour/js-structures/blob/master/guides/react-anti-
patterns.md#pure-render-immutability
Optimizing React Rendering
124
Synthetic Events
The following piece of code will log null because event has been reused inside the
SyntheticEvent pool:
function handleClick(event) {
setTimeout(function () {
console.log(event.target.name);
}, 1000);
}
To avoid this you need to store the event’s property you are interested in inside its
own binding:
function handleClick(event) {
let name = event.target.name;
setTimeout(function () {
console.log(name);
}, 1000);
}
Related links:
React/Redux: Best practices & gotchas
React events in depth w/ Kent C. Dodds, Ben Alpert, & Dan Abramov
125
Related Links
Related Links
React in Patterns by krasimir
React Patterns by planningcenter
reactpatterns.com
10 React Mini-patterns
126