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.
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
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
, andno-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
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
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
😱 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
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
😆 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 thebuttonText
andlink
properties since both properties were defined as string data types prop types in theLinkButtons.js
component file. Here’s what that looks like.
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 asobject
(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 beyondobject
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
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 theheaderBar
component. - I had not defined
propTypes
ordefaultProps
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.
If you’d like to make sure you never miss an article I write, sign up for my newsletter here: https://paigeniedringhaus.substack.com
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
- GitHub repo of MERN application
- ESLint Documentation
- Airbnb ESLint, npm
- Airbnb ESLint, GitHub
- Airbnb JavaScript Style Guide, GitHub
- Syntax podcast
Top comments (0)