Joshua's Cheatsheets - React / JSX - Cheatsheet
Light
help

Other resources

What & Link Type
"The React Handbook" by Flavio Copes - Online version PDF signup
   ---> Amazing resource!
Guide
"React for Vue Developers" by Sebastian De Deyne Guide / Cheatsheet

Binding template literal

Binding template literal to property expecting string: You have to use double brackets to "break out" of JSX and into regular JS. Instead of:

<SEO title="`${props.pageContext.slug}`" />

You need:

<SEO title={`${props.pageContext.slug}`} />

Logic within JSX

Creating unique keys

You want a unique identifier, which is actually harder than one might expect to create. Using the index provided within a loop is not recommended, and even combining with something like (new Date()).getTime() is not guaranteed to be unique.

There are tons of packages out there that you can drop in to create unique Ids. Or just make a composite key out of enough unique parameters to ensure non-duplicates.

Misc

  • You can now use empty elements, known as fragments, to wrap siblings:

    • <><div></div><div></div></>

Asset management and usage

You have two main options when it comes to asset management:

  • Public Folder: Place in /public

    • Pull into HTML with %PUBLIC_URL%
    • Pull into JS with process.env.PUBLIC_URL
  • Bundling: Place asset files alongside JS, in /src

    • Pull into JS by using import at top of file with relatively path
    • Pull into css (e.g. for background image) with relative path

The second option is always preferred, since it uses webpack to bundle assets and will help keep the size of your app down by only bundling assets that are actually used (as well as some other tricks).

Importing assets in JS or CSS

Examples:

JS:

import background from './assets/background.jpg';
// ...
render() {
	return (
		<img src={background} />
	)
}

CSS:

#main {
	background-image: url(./assets/background.jpg);
}

Getting around method binding of this

A common issue with React is preserving the value of this, especially when it comes to event handlers, like onClick.

If the callback you are assigning uses this within its body, you will have issues if the value of this changes (most often in a Cannot read property '___' of undefined error).

Here are some ways to ensure the value of this stays the way you want it to:

Explicit, with .bind() on the attribute

The older method was commonly to use .bind() to explicitly bind the value of this at the point of attaching the handler. That might look something like this:

<CustomComponent onClick={this.handleEvent.bind(this)}>

ES6 Class binding

If you are using the new ES6 class syntax, you have all the other options, plus a few more. Let's say this is our base code:

class MyComponent extends React.Component {
	constructor(props) {
		super(props);
		this.state = {counter: 0};
	}

	handleClick(evt) {
		const updatedCount = this.state.counter + 1;
		this.setState({
			counter: updatedCount
		});
		console.log(this.state.counter);
	}

	render() {
		return (
			<button onClick={this.handleClick}> Counter + </button>
		);
	}
}

One option is to use .bind(), in the constructor:

constructor(props) {
	super(props);
	this.state = {counter: 0};
	// ADDED:
	this.handleClick = this.handleClick.bind(this);
}

Another option is to turn the handleClick method, into a member, that is the value of an arrow function, thus automatically binding this to the class:

// Rest of class definition
handleClick = (evt) => {
	const updatedCount = this.state.counter + 1;
	this.setState({
		counter: updatedCount
	});
	console.log(this.state.counter);
}
// ...

Technically, this is actually an ES6 public field, which is, as of 2019, in an experimental stage, so while it is well supported with transpiled JS/TS, it has limited native browser support.

Inline arrow functions

One of the benefits (or drawbacks) of arrow functions is that they lexically bind this - automatically. So, if you do:

<CustomComponent onClick={(evt) => {
	this.handleEvent(evt);
}}>

It doesn't matter if CustomComponent has a different this scope, becaues the arrow function binds the callback where you defined it!

Use createReactClass

If you use createReactClass, you generally don't have to worry about this issue, as createReactClass uses autobinding, which basically does .bind() for you.

More reading


Computed properties

Unlike Vue, which has a specific syntax for computed properties, React doesn't really care how you try to formulate values based on computed state properties.

ES6 Class - Getter

With the new ES6 class based approach, a very clean solution is to use getters, with something like:

class MyComponent extends React.Component {
	// ... class stuff
	get isAdult() {
		return typeof(this.state.age) === 'number' && this.state.age > 18;
	}
}

Within the render function itself

There is nothing preventing you from computing a value within the render function itself. For example:

class MyComponent extends React.Component {
	// ... class stuff
	render() {
		const isAdult = typeof(this.state.age) === 'number' && this.state.age > 18;
		return (
			<div>
				Is adult = {isAdult.toString()}
			</div>
		);
	}
}

As a function

Another vanilla solution here is to simply use a function to return the computed value, rather than anything else. How you declare this is up to you:

  • Explicitly, with function myFunction(){}
  • As a ES6 class member

    • public isAdult() {}
  • With an arrow function to bind this

    • const isAdult = () => {};
  • Etc.

To use within your render method, simply make sure you actually execute it by following it with the parenthesis and arguments if applicable.

State management system

If you are using a dedicated state management system, there is a chance that what you are using might already have something in place to not only provide explicit computed properties, but also optimize them, to prevent redundant expensive re-calculations.

For example, if you use MobX, make sure to check out this page on computed values.

Futher reading:

Markdown Source Last Updated:
Tue Nov 19 2019 19:23:07 GMT+0000 (Coordinated Universal Time)
Markdown Source Created:
Wed Aug 21 2019 20:31:01 GMT+0000 (Coordinated Universal Time)