3 Ways to Write Elegant JavaScript Code
It’s time to put an end to spaghetti code.
Whenever I finish building a project or take a look at some older code, I always try to find ways to refactor and improve readability. Methods of doing this can include writing custom React hooks, wrapping repeated code into subroutines, and others. In this article, I’ll be sharing three common methods to modularize and improve the maintainability of your code. Let’s dive in.
1. Use TypeScript
This may come as an eye-roller for some, but TypeScript alleviates many of the issues that make JavaScript an unsafe language in some cases. It also makes the intentions of your code clearer. Let’s take a look at a JavaScript example of a simple React component People
:
We can see here that People
accepts peopleList
as props, which is a list of objects each representing a person which will be rendered as a <ListItem />
. All of this is fine, but what if a property is missing from one of the people? What if a person has undefined
as their occupation or salary? A lot of you might be thinking that we can just use prop-types
to handle this, but in my opinion, TypeScript provides a more elegant solution. Let’s look at the same People
component, written in TypeScript:
In this example, we’ve defined an interface Person
with optional properties (denoted with ?) to inform the compiler that a person in peopleList
might only contain a subset of the properties in Person
. We’ve also defined a PeopleProps
interface that specifies the type of prop People
should receive, which is a Person
array. As a result of this, the People
component is more flexible and robust.
2. Use IIFEs
If you’re familiar with Immediately Invoked Function Expressions (IIFE), then you definitely know how useful they can be as a clean way to compose two statements into one. Let’s say you wanted to initialize an array with some external data:
In this example we’ve defined a function initList
which returns an array containing the external data. We then call the function and store the result in dataList
. It’s not that there’s anything wrong with this code, but it could be written more elegantly, like so:
Here, we save a few lines by assigning dataList
to an anonymous function that is immediately invoked.
3. Separation of Concerns
It is always important to separate the concerns of functionality in a codebase, especially when working with projects of increasing complexity. It is typically not ideal to have a function perform multiple tasks at once, especially if they are in no relation to each other. Let’s analyze a bad React example of a component Example
that is dependent on some external API data:
The reason why this is a bad example is because the Example
component should only be responsible for displaying the data on the screen, not fetching the external data. This creates clutter and makes the component harder to debug. Fortunately, we can fix this by writing our own hook that contains the logic for making a post request. This hook will be a function that accepts a url and options, makes the post request, and returns the data like so:
Now that all of the logic to call the API is in this custom hook, our Example
component now looks like this:
With usePost
abstracting away the post request logic, the Example
component is now only responsible for displaying the data. The codebase just became much more maintainable by making this change.
If you made it here, thanks for reading! I hope you found this post insightful. Enjoy the rest of your day.
More content at plainenglish.io