Popular ES6/React lint errors
Recently, I was tasked with converting a 15,000+ line jQuery-React application into a React-Redux application. This involved a pretty big code overhaul and I took this as an opportunity to implement more strict lint rules. This not only helps keep the code clean and consistent, but also helps a lot when working on application migration; catching a lot of easy mistakes for you. I’ve rounded up 5 of the most popular lint errors in the application in hopes that it will be useful for React/ES6 beginners or developers working on apps that have no or relaxed lint rules.
React/no-access-state-in-setstate
yannickcr/eslint-plugin-react
eslint-plugin-react - React specific linting rules for ESLint
github.com
This one can be tricky for beginner React developers, or honestly any skill level, and kinda difficult to debug. An easy example to explain this would be a React event handler used to increment a counter in the component state:
This issue here is explained in the setState()
API documentation:
setState()
does not always immediately update the component. It may batch or defer the update until later. This makes readingthis.state
right after callingsetState()
a potential pitfall.
To avoid issues with asynchronous or batched setState()
calls, you can pass a callback function to setState()
and use the first parameter, prevState
, to create the new state:
No-shadow
This one is pretty straightforward. A lot of times, i’ve seen this rule violated using one of the map, filter, reduce functions.
const x = [1,2,3]
const y = x.filter(x => x < 2)
The variable inside the filter function has the same name as the array defined above. This is called “shadowing variables”. The lint errors can easily be eliminated by choosing another name that hasn’t been defined previously. However, the snippet below does not break the no-shadow
rule because the notShadowed
variable is only defined in the scope of the filter functions; as opposed to the scope of the parent function.
const func = x => {
const y = x.filter( notShadowed => notShadowed < 2);
const z = x.filter( notShadowed => notShadowed > 2);
return [...y, ...z];
}
Prefer-const
Surprisingly, this was the most popular lint error in the application. But, since a lot front-end developers that started before the release of ES6 are used to using var
for everything, I can see how starting to use two different variable declarations can be tricky. Also, because const
has more restrictions than let
, no variable re-assignment, it’s probably not a coincidence that developers skip using const
all together and decide to use let
for all variable declarations.
Just to give a quick overview, we should be using const
to declare variables that will never be reassigned. On the other hand, let
should be reserved for variables that will be reassigned:
const func = () => {
const x = 5; // assigned once
let y = 5; // assigned twice y = x * 2; return y;
}
React/prefer-stateless-function
yannickcr/eslint-plugin-react
eslint-plugin-react - React specific linting rules for ESLint
github.com
The first line in the markdown file linked above explains:
Stateless functional components are simpler than class based components and will benefit from future React performance optimizations specific to these components.
In my opinion, stateless functional components are cleaner and easier to read. If you don’t need lifecycle methods or state, you may be better off using a stateless functional component. Also, according to an article by Phillipe Lehoux, It seems that you also can benefit from SFCs not by calling the function directly as opposed to using the React.createElement
syntax. Here’s an example:
// Bad
class MyComp extends React.Component {
render(){
return <div style={this.props.style} />
}
}/* ---------- */// Good
const MyComp = ({style}) => (<div style={style} />)// Can be called like
<MyComp style={{color: 'red'}} />// Or (avoiding React.createElement)
const style={{color: 'red'}};
MyComp({style});
No-use-before-define
This one may be the simplest of the bunch. It means almost exactly what the error says, we should not be using things before they’re defined. I have seen this one most commonly in files that have functions that call sibling functions within the same file.
// Bad
const doThis = () => butDoThisFirst()
const butDoThisFirst = () => 5// Good
const butDoThisFirst = () => 5
const doThis = () => butDoThisFirst()