Things to stop/start doing in React

Rowan 🤖
Technical Credit đź’¸
5 min readMay 9, 2018

It is pretty common in tech for a once popular way of doing things to suddenly become a faux pas as the industry progresses, and React is no different in this respect. The style I have been using in React this year looks quite different to the style I was using a year ago. There haven’t been any major shifts like there was with the removal of mixins, it has been more of a gradual evolution that has just made slightly tedious/verbose code a bit nicer. There is nothing wrong with most of the “old” way of doings things, but it might be worth considering some of these niceties if you haven’t already.

Note: These examples are based upon React 16.3 with the React App Babel preset, but most should still be applicable to earlier versions and similar Babel presets.

Banish the constructor: Part 1

If you are only using the constructor to set your state, then you might not need the constructor at all. You can instead initialise the state as a class property (you can still access this.props if required):

class ComponentOld extends React.Component {
constructor(props) {
super(props);
this.state = { say: this.props.say };
}
render() {
return <div>{this.state.say}</div>;
}
}
class ComponentNew extends React.Component {
state = { say: this.props.say };
render() {
return <div>{this.state.say}</div>;
}
}

The above two components are equivalent, but to me ComponentNew is a lot clearer without the constructor.

Bonus points: If you still require a constructor, but the constructor doesn’t make use of this.props, then you can omit props from the constructor definition.

Banish the constructor: Part 2

In order to make this work in the context of the event handler, it is quite common to “bind” it in the constructor like so:

constructor() {
super();
this.handleClick1 = this.handleClick1.bind(this);
this.handleClick2 = this.handleClick2.bind(this);
}

This kind of gets my goat as it just seems like “unnecessary” noise that starts to snowball as you create more event handlers and defeats my goal of not having a constructor.

Two approaches to remove this from the constructor are shown below:

handleClick1 = this.handleClick1.bind(this);
handleClick1() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn,
}));
}
handleClick2 = () => {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn,
}));
};

In our first approach (demonstrated by handleClick1), we have succeeded in removing the constructor by moving the binding to a class property. This is OK, but if we continue with this approach then we will have a class property for each function that we need to bind, and we aren’t really in much of a better situation when compared with doing it in the constructor.

In the second approach, we still use a class property, but this time our property is an arrow function handleClick2. These means two things :

  1. We get the this value that we actually want GOOD
  2. The arrow function is a property and not a method BAD???

Point number two might not be desirable as our arrow function doesn’t get added to the object’s prototype. This means that each instance of our component will get it’s own full implementation of the function, rather than a reference to a single implementation in the prototype i.e. higher memory usage.

The second approach is still my preferred as I don’t really see memory usage as an issue unless your component is repeated a lot on a page e.g. a table row — and even then, I would prefer less code over making premature optimisations.

PropTypes as static class properties

Even with Flow and TypeScript available, I still prefer using the PropTypes library in a lot of scenarios due to its simplicity. Many examples show propTypes being added as a static class property outside of the class definition, but we can now include it inside of the class definition.

class GreetingOld extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
GreetingOld.propTypes = {
name: PropTypes.string,
};
class GreetingNew extends React.Component {
static propTypes = {
name: PropTypes.string,
};
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}

The components are once again equivalent, but I find GreetingNew to be a bit tidier with everything “contained” within the class definition.

Unsafe Lifecycles

React 16.3 introduced some changes that deprecate the following lifecycle methods:

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

These are deemed to be “unsafe” as they are often misused and may cause problems with the upcoming async rendering feature. Read the official blog post for a migration path.

Using i as a Key

If you’re using map to render a collection of elements, then you will be familiar with having to add a key attribute to each element (if you’re not familiar, then read this). In the absence of an appropriate key in your data, it can be quite tempting to just use the item’s array index as the key like so:

myData.map((data, i) =>
<div key={i}>
{data.value}
</div>
);

However if your data is not static, or if you have any client filtering or ordering, then you might run into rendering issues where the wrong data is displayed! To overcome this you really need to find something that can be used as a unique and reliable key. The below post has a more detailed explanation and solution.

Asynchronous componentDidMount

It’s probably not news that instead of using promises with callbacks for asynchronous tasks, you can use async/await. But for some reason I only just realised that you can safely mark componentDidMount as async and use it like so:

async componentDidMount() {
const res = await fetch('/Home/Test');
const something = await res.json();
this.setState({something});
}

This is tidy, but isn’t a very common scenario for me these days as I like to use the amazing Redux-Saga library for my side effects.

Your results may vary

Apart from the deprecated methods, most of these suggestions really come down to your own personal preferences and needs. I’m a big fan of trying new approaches and writing less code — especially if it makes it more readable, so please leave a response with any tips that you have.

--

--