In a recent lecture on basic graph theory the professor mentioned a little algorithmic game called Bridget. It was claimed that there is a winning strategy. I could not figure it out (yet), but built a browser based interface for the game instead. I had it up and running fairly quick and was able to try out different strategies. I implemented it in React, although I only understand some basic principles of the framework. But I really like it so far and want to get better at it. So I decided to apply some React coding standards to it using ESLint and then work on some of the repeating issues. I used the ESLint recommended and Airbnb JavaScript rules. For more details have a look at the repository on GitHub. The codebase is still messy, but it was a fun exercise in refactoring old patterns into new ones. This the post is simply a list of some of the refactoring steps I took based on certain ESLint errors.

Purely functional components

The term sounds complicated, but it is a really simple thing. What happens to an ES2015 class when you only provide the render method and define nothing else like other methods or state? It will create an object with some props as attributes and then call its render method which returns some JSX based on these props. It seems more natural to just map the props onto the JSX, doesn’t it? That is what functional components do. They are functions that map props to JSX and can be used like any other React component. Here is how such a refactor might look:

// Using the full class API
class myComponent extends React.Component {
	render() {
		return <p>What a {this.props.type} component </p>
	}
}

// Using a functional component
const myComponent = props => (
	<p>What a {props.type} component</p>
)

No more .bind(this) on class methods

The old React API to create a component was React.createClass. This would automatically bind all class methods onto the instance. Using the new ES6 class API does (can?) not provide this feature. Coming from the old pattern, I would just do this myself all the time now. The Function.prototype.bind method creates a brand new function object with a pre-defined this context. Doing this from inside a render method of some React component will create a new Function on every re-render of this component. Most of the time, this is not what we want and it definitely was not what I wanted. They way I went with for now is the following:

class myComponent extends React.Component {
	constructor() {
		super()
		// Replace existing method with hardbound version of it
		this.someMethod = someMethod.bind(this)
	}

	someMethod() {
		// Do something that relies on 'this'
	}
}

Note: If you call this.someMethod() from somewhere, it will work without the hard binding in the constructor. But for example click handlers for buttons are not called as methods, but by some event emitter. For these cases, hardbinding the context is necessary if you want to use instance methods. 1

Do not use array indices as keys in maps

A very common pattern is to map an array from props onto a list of elements. React requires you to provide a unique identifier for each child in the iteration. It must only be unique relative to the other children of the same iteration, not globally. It seems straightforward to use array indices as keys right? Turns out that is probably not what you want: 2 Assume one element is pushed to position 0 and all the others are shifted to right. Using array indices, this will tell React that each and every element of the array changed and trigger unnecessary re-renders, while in reality just one element changed. Therefore a true identifier of each element should be used that sustains potential repositioning within the array. In my case, the error was a false positive though. The iteration is used to render rows and cells of a table so the indices actually are the keys. Maybe that is a hint that my table rendering is not quite optimal? I am not sure, but I decided to ignore this error.

Linters not only help in writing, but also learning code

I find it extremely impressive what static code analysis tools like ESLint can do. They are certainly helpful for consistent code formatting but they can even recognize design patterns and give you hints about them. This refactoring exercise made me realize that a linter with this feature can be used to learn new patterns or find faults within your existing ones. Besides that I also enjoyed working with React once more and decided to aim for a better understanding of it. The next step I will take in this direction is to study JSX more in-depth. I often come across little things that do not work as I expect them to. Time to learn how this language mix magic happens!