First published February 17, 2019 in ITNEXT

How ESLint Makes Me a Better React Developer

JavaScript's loose standards are a blessing and a curse.

No ESLint errors success kid

Clean-er code: the wake up call

I was a little late to the React party, I only started learning it in earnest, about 10 months ago. Yes, I’d heard about it long before then. Yes, I’d had co-workers, casual acquaintances, and the two developers putting out my web dev podcast of choice, Syntax, tell me how great it was. Yes, I’d heard Facebook, which at that time had yet to reveal of its less-than-savory-doings, had created it, and kept improving on it.

But as anyone who’s been a web developer for longer than six months knows, there’s an absolute ton of JavaScript frameworks out there that had a brief moment in the sun, only to be obscured weeks or month later by the new hotness. So I sat on my hands, waited to see if React was worth investing my time in learning, and laughed every time this meme came across my Internet feeds.

Parody O'Reilly cover

This image still makes me smile whenever I see it. O’Reilly parody covers are the best.

When it became apparent that React was the new JavaScript powerhouse of choice and wasn’t going away anytime soon, I finally got on board and started teaching it to myself. For the past 10 months or so, I’ve been learning React on the side while supporting an AngularJS 1.5 application at my current company.

And having to work with that monolithic, two-way data binding, AngularJS application, chock full of business logic, while building smaller, cleaner, unidirectional data flow, React side projects reinforced what every one else had been telling me all along. React is way better.

Recently, I was feeling pretty good about my own React / JavaScript knowledge and coding abilities. By no means am I an expert, nor have I used some of React’s most recent advancements like Hooks, but I can talk knowledgeably about state and props. I can discuss different lifecycle render methods and what they’re good for. Heck, I can even debate Redux versus the Context API for state management, and why things like defined prop types are beneficial.

I’ve written a full-stack, user registration app as a learning tool and I am proud of it. It’s React and ES6 on the front end, Node.js on the backend, and a MySQL database with the Sequelize ORM to handle database interactions. I implemented Passport.js middleware for JWT authentication and Docker Compose to spin the whole application up at once. I also added in password reset via email functionality with Nodemailer and Swagger API endpoint testing.

I’ve done a lot with this little app, learned a lot along the way, and written a lot of articles about my learnings (all linked above). But then, I added ESLint into my application, thinking it would be a good way to make sure my code was well written...

And once again, I was humbled and taught how to write better JavaScript code. That’s what I want to talk about today: how ESLint can make me (and you) a better developer.

ESLint: 21st century rules for ES6 JavaScript & beyond

ESLint logo

What is ESLint?

If you’re not familiar with ESLint, you can read this handy post I wrote a few months ago. The post was more to do with using both ESLint and Prettier in the Visual Studio Code IDE to produce consistent, clean code across development teams with little effort on the part of the developers, but it still explains how ESLint works.

In a nutshell:

Linting tools like ESLint allow developers to discover problems with their JavaScript code without executing it. —ESLint site

ESLint is a file in a project repo called .eslintrc with a list of linting rules that runs through the project’s JavaScript code and finds problematic patterns or code that don’t adhere to certain style guidelines set forth by those rules. Then it alerts developers so they can fix it the errors.

It will not (normally) rewrite or reformat code like Prettier. Nor will it tell you if you have bad business logic. But it will tell you if curly braces are missing, return statements are unreachable, or objects / arrays could be destructured, among other things.

Why ESLint is awesome

This is awesome because not only does ESLint identify ways to make code better, but if you don’t need or don’t agree with certain rules, they can be changed or ignored (either for the line, for the whole file, or for the whole project).

None of the rules depend on each other, they all function independently, and some rules can even fix the code themselves to fall in line with the prescribed rules.

Airbnb ESLint

The ESLint rules that Airbnb abides by are considered among many as the gold standard for React applications. They are strict, they are unforgiving and they are thorough. They are so popular, in fact, that Airbnb created their ESLint config as an npm package that has over 1 million weekly downloads, as I write this article.

They also have an entire JavaScript style guide on GitHub that has some very good advice in it for writing code. But that’s a different rabbit hole than the one I’m going down today.

Since I felt like holding myself to high standards (being a masochist), I decided to use Airbnb’s ESLint rules as the starting place for my own .eslintrc file for my full stack JavaScript project. Boy, did I learn a lot when I turned on the linter...

Before and after ESLint's cold, brutally honest linting

My ESLint setup & dev dependencies

Before I could get linting for my React application going to reveal my own code’s shortcomings, I had to download a few dev dependencies for my package.json file and set up my .eslintrc file.

Dev dependencies

I used Create React App to create the initial front end for my full stack application, so I only had a few additional dependencies I needed to add to my package.json file to make Airbnb’s ESLint config work.

npm install --save-dev eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react

.eslintrc file

Then, once all the package were installed, I set up my .eslintrc file like this.

{  
  "extends": "airbnb",  
  "parser": "babel-eslint",  
  "env": 
    {    
      "node": true,    
      "es6": true,    
      "browser": true  
    },  
  "rules": 
    {    
      "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],    
      "implicit-arrow-linebreak": "off",    
      "comma-dangle": "off",    
      "indent": "off",    
      "no-trailing-spaces": "off"  
    }
  }

That’s really all the setup I did. I added "extends": "airbnb" as prescribed by the Airbnb’s documentation, added in that I was transpiling my ES6 code with babel, listed the environments and added a few additional rules to override the Airbnb settings.

Most of these rules were overwritten because I also use Prettier’s code formatting on save in my VS Code setup, and if I didn’t turn off the rules in ESLint, Prettier would continue to reformat code and break the rules every time I saved a file. A minor inconvenience though.

The rules I set

  • I extended the react/jsx-filename-extension rule to apply to files ending in both .js and .jsx because all my files which include JSX end in .js.
  • I turned off implict-arrow-linebreak because Prettier reformatted it on save.
  • I turned off comma-dangle, indent, and no-trailing-spaces for the same reason.

Beyond that, there were one-off rules that ESLint highlighted, which I turned off by file or by line when I needed to (such as console.log). I’m sure you’ll also come upon situations that dictate such exceptions as well.

Without ESLint enabled

Now, let’s see how my code looked before I enabled ESLint in my project.

Here’s an example of two of my React components. The first is the home page file, the second is the header bar, which is a reusable component across the whole application.

Home.js file

Code snippet of the home page, no ESLint yet

This code looks pretty nice and unassuming right? Nothing particularly wrong with it.

This file looks OK at first glance, it seems clean and well formatted. Simple, straightforward. One prop that gets passed to the header bar itself, styling for the buttons comes from other reusable components. All pretty self-explanatory.

HeaderBar.js file

Code snippet of the header bar component, no ESLint yet

Again, this code looks OK to me...

The header bar file is much the same. Nice, well known React create class component structure, some props for the header title, a default to fall back to if one wasn’t provided. Seems fine to me.

With ESLint enabled

Then, I turned on ESLint in my project (all the details on how to do this in VS Code are here), and I saw the following horrors on pretty much every file in my project…

One of the many things I appreciate about the VS Code IDE is that it has its own separate “Problems” tab where all of these ESLint errors show up. And when I hover over all the angry red squiggles or click on any of the errors, I’m directed right in the code to where those errors are. Presumably to fix them (or ignore them if necessary).

Clicking the little lightbulbs that appear over the angry code will show you what ESLint rule is being broken and give you the option to ignore the rule for the line or whole file or go to the ESLint rule documentation to learn more about how to fix the error.

Home.js file

Code snippet of the home page, ESLint errors abound

😱 ESLint does not feel the same way about this code that I did. All the things are wrong.

Um…what is going on here? Why are there so many red squigglies everywhere?!?!

Header.js file

Code snippet of the header bar - the whole thing is an ESLint error

Ugh, look at all those red lines...

😱 And here too? Really?!? Such a simple component, and this is what I see? What gives ESLint??

After I’d gotten over my initial shock and indignation at ESLint’s very brutal and unforgiving code review, I set to work fixing the errors and learned how to write better React in the process.

I did it through a combination of reading the ESLint error documentation (which VS Code’s ESLint lightbulb extension linked me right to) and checking Stack Overflow for examples of how to write things the right way based on the rule being broken.

Fixed after ESLint

Let’s see what the new pro-ESLint-ed code looks like for the same files.

Home.js file

Code snippet of the home page after fixing the ESLint errors

😆 Much nicer. Look — it’s clean, it’s pure and stateless, it’s easier to read.

Here’s what changed.

  • ESLint detected this home file was actually a pure, stateless component that didn’t need to be a React class. Instead, it could be written as a const variable: const Home.
  • It also identified that the <LinkButtons> didn’t need curly braces around the buttonText and link properties since both properties were defined as string data types prop types in the LinkButtons.js component file. Here’s what that looks like.

Code snippet of the link button props

Here’s the prop types for `LinkButtons` that wasn’t previously defined before ESLint was in play.
  • You’ll also notice in the code snippet above, the ESLint rule I disabled regarding buttonStyle: // eslint-disable-next-line react/forbid-prop-types. I did that because ESLint frowns on prop types described only as object (it wants greater specificity), but since I was using the button styles provided by my React Material styling dependency, I chose not to go deeper in defining the prop types beyond object in my own prop types.

Happily, with these changes, the problems and red squiggles displayed in VS Code, were gone, for this file. And I have to admit, the code does look cleaner than my original React code.

HeaderBar.js file

Code snippet of the header bar after fixing the ESLint errors

Again, looks better. Props and default props are defined, the component is stateless, title is destructured from props object being passed in.

Here’s the header bar reusable component rewritten after ESLint as well.

  • This component too, could be written as a stateless, functional component, instead of a React class. It became const HeaderBar.
  • ESLint instructed me to use ES6 object destructuring to take just the title property from the object that I was passing in to the headerBar component.
  • I had not defined propTypes or defaultProps for the component, the kind of typechecking that helps prevent bugs from unnecessarily entering code just because an unexpected JavaScript type was passed as a prop.

After these changes were made, my code was deemed acceptable by ESLint’s strict standards.

Now, imagine if you will, a series of similar errors in pretty much all the files in my code base. But these errors helped me learn how to recognize and write better JavaScript and React code, and for that I am grateful.

My project was small enough I could go through file by file and fix the issues in just a few sessions, but if are implementing ESLint into a large, already existing code base, it might make more sense to just fix the files you’re currently working on as you implement new features, until all the files can be fixed to adhere to the new ESLint rules. Instead of trying to fix them all in one fell swoop.

Conclusion

JavaScript is an interpreted language, and it allows developers a lot of leeway that strongly typed languages like Java won’t put up with. Most of the time, I appreciate this flexibility, but it does open up opportunities for bugs strongly typed languages don’t have to deal with.

As usual, when I started to feel too confident in my JavaScript abilities, ESLint came along and took me down a few notches. But the harshness of the Airbnb linter I view as a good thing.

It taught me how to better recognize and refactor React classes into stateless components, how to take advantage of ES6 features like object destructuring, and how defining prop types can prevent unnecessary bugs before they happen. It has improved my code and my coding, and will continue to do so in the future.

Check back in a few weeks, I’ll be writing about React or something else related to web development.

Thanks for reading, I hope this helps convince you to give ESLint a try with your own React and JavaScript projects and improve your own projects and coding abilities.

References & Further Resources

Want to be notified first when I publish new content? Subscribe to my newsletter.