Small Tips to Write Better React Code

Learn how to use some JavaScript features to clean up your code

Feature Image

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

Join the Free Newsletter

A free, weekly e-mail with the best new articles, courses, and special bonuses.

We won't send you spam. Unsubscribe at any time.