Today we are going to talk about some of my favorite tips, which are super easy to implement or to follow, and that can make your JavaScript code cleaner. Also keep in mind some of the things we are going to learn today apply to JavaScript in general, though the article will focus on React.
Object destructuring
To get started we will review object destructuring, one of my favorites actually, that can help to keep the code small, clean, and elegant. This topic I love so much that I actually made a whole post about it here: Write Cleaner Code By Using JavaScript Destructuring.
Destructuring allows you to break down complex structures into simpler parts. Let's take a look at an example:
const { title } = props
console.log(title);
A common place where React developers use this technique is with props. Though some people may argue that you lose context when you split the variables, it is usually the case in React, that the context is inherited by the component itself. Let's take a look at an example to show what I mean.
First, let's write a simple component to show Task information on the screen:
function TaskView(props) {
return (
<h1>{props.task.title}</h1>
<p>{props.task.description}</p>
<span>{props.task.completed ? 'Completed' : 'Pending'}</span>
)
}
It is indeed very simple, however, look at how we repeat props all the time, not very pretty. Let's look at another way to implement this:
function TaskView(props) {
const task = props.task
return (
<h1>{task.title}</h1>
<p>{task.description}</p>
<span>{task.completed ? 'Completed' : 'Pending'}</span>
)
}
It's a bit better but still, we have tasks everywhere. Now someone who perhaps doesn't know destructuring may be tempted to do something like:
const title = props.task.title
const description = props.task.description
which adds too much overhead to the declarations. Let's now see how the component looks like when using destructuring.
function TaskView(props) {
const { title, description, completed } = props.task
return (
<h1>{title}</h1>
<p>{description}</p>
<span>{completed ? 'Completed' : 'Pending'}</span>
)
}
Now the code is very simple, we keep the JSX very clean from the rest, and we are still in context. It's perfectly understandable that when we say title
we are talking about the Task
as is what the component is all about. So keep your names clean, and structure well your components and you will love this feature.
Simplify your conditional statements
In this section, I want to talk about 3 different scenarios that can help us increase the readability of our code, and it's so easy, though many times we forget to do it.
Conditional execution
It is normal that at some point we need to run a statement only if a certain condition happens to be true. Usually, it goes something like:
const isFive = (num) => num === 5
if (isFive(5)) {
console.log('It is the number five!')
}
Now, there's nothing inherently wrong with that code, however, it can be simplified a bit:
const isFive = (num) => num === 5
isFive(5) && console.log('It is the number five!')
Nice, but how does it work? JavaScript as many other languages, read conditional statements such us &&
or ||
in order from left to right, and they exit at the time they can invalidate the arguments.
Let's see an example of this with all conditionals:
const t = 1
t === 1 && t === 2 && t === 3
In that example, JS will first take the first expression t === 1
, since that expression is truthy and we have an and
conditional, it needs to evaluate the next expression, as we need to guarantee they are all truthy. When it evaluates t === 2
, which is falsy, it doesn't need to evaluate t === 3
at all, it can save that compute as we know the whole statement happens to be false
.
Amazing! now let's learn something more about this. It is very common on the internet to see examples of this, however, did you know you can also use the ||
operator as well?
const isFive = (num) => num === 5
isFive(5) || console.log('It is the number five!') // does not execute the console.log
isFive(10) || console.log('It is not the number five!') // it executes the console.log
Did you notice that what we just did would be equivalent to apply a not to our first example?
const isFive = (num) => num === 5
isFive(5) && console.log('It is the number five!') // it executes the console.log
!isFive(10) && console.log('It is not the number five!') // it executes the console.log
Ternary operator
The conditional (ternary) operator is the only JavaScript operator that takes three operands: a condition followed by a question mark (?), then an expression to execute if the condition is truthy followed by a colon (:), and finally the expression to execute if the condition is falsy.
This is very commonly used to show different statuses or components to the user depending on a conditional statement. Though I don't always recommend to use the ternary operator, sometimes a good old fashion if does the job very well. It can be extremely useful for small things.
Take a look a the following example:
if (completed) {
return 'Completed'
} else {
return 'Pending'
}
Another variation of that, which I still see around is:
if (completed) { return 'Completed'} else { return 'Pending' }
I'm not here to judge, but that can get real messy. Let's take a look at a way using the ternary operator
return completed ? 'Completed' : 'Pending'
Much nicer!
Optional Chaining
Last but not least, we have optional chaining (?.
) that allows reading the value of a property located deep within a chain of connected objects without having to expressly validate each reference.
In plain English, it helps to avoid a bunch of if
statements just to make sure we have a value on a nested property. Let's look at an example:
const juan = {
name: 'Juan',
marriedTo: {
name: 'Diana'
}
}
console.log(juan.marriedTo.name) // Diana
console.log(juan.divorcedFrom.name) // Cannot read property 'name' of undefined
Ups.... when we tried to access the name of the person we are divorced from, we get an error, because divorcedFrom
in our case is undefined. Normally we would solve it like this:
if (juan.divorcedFrom) {
console.log(juan.divorcedFrom.name)
}
But that can also get out of hands by adding a lot of ifs just for this purpose. There is a better way using optional chaining.
const juan = {
name: 'Juan',
marriedTo: {
name: 'Diana'
}
}
console.log(juan.marriedTo?.name) // Diana
console.log(juan.divorcedFrom?.name) // undefined
And this can apply to multiple levels
juan.marriedTo?.disvorcedFrom?.kids
Very nice! Let's move on with the next topic.
Spread Operator
There is no React app without making use of the spread operator, maybe that's exaggerated, but the spread operator is widely used in react applications, especially when working with reducers, though it is much more than just for that. This is another topic which I covered extensively in the article How to Use the Spread Operator (...) in JavaScript. I really recommend that you read it, it's pretty cool and covers the topic in detail.
The spread operator allows you to expand an iterable object into a list of its individual elements. Let's better take a look into some examples:
function sum(x, y, z) {
return x + y + z
}
const numbers = [1, 2, 3]
console.log(sum(...numbers)) // 6
In this case, what we are doing is to transform an array
into separate variables that are passed to our sum
function. It's a pretty neat trick. But we can also apply it for objects:
const obj1 = { foo: 'bar', x: 42 }
const obj2 = { foo: 'baz', y: 13 }
const copyObj1 = { ...obj1 } // This copies all the properties of obj1 into a new object.
const merged = { ...obj1, ...obj2 } // This merges all the properties of obj1 and obj2 into a new object.
console.log(merged) // {foo: "baz", x: 42, y: 13}
Because we can use this to create new objects or arrays, its ideal to use with Redux, as we can avoid mutating the original objects.
Template Literals
Though very popular and beginners friendly, no list would be completed without them. Template literals are basically strings, but not any string, they allow embedded expressions. Let's take a look.
console.log(`this is a string literal`)
In its more basic form, a string literal is just a string, however, note that for it to be a string literal it must use `
instead of "
or '
. It's a small detail but makes a huge difference.
String literals, for example, support multi-line strings:
console.log(`line 1
line 2`)
Or you can also embed expressions
const a = 10
const b = 25
console.log(`a: ${a} and b: ${b} but more importantly a+b = ${a+b}`) // a: 10 and b: 25 but more importantly a+b = 35
Really cool!
Conclusion
JavaScript is packed with useful operators, expressions and tricks to power up our development skills, and writer cleaner code. It is also true that some of the things I mention can be personal judgment, but if you look at the React code written on very popular projects you will see they apply these small things all over the place. So they are really good to learn and implement when you write your next React component.
Thanks for reading
If you like the story, please don't forget to subscribe to our free newsletter so we can stay connected: https://livecodestream.dev/subscribe
Top comments (1)
Can shorter by object destructing in parameter list. Bonus Fragment: <> fix error