David Hockley

The 7 JavaScript Skills You Need for React

There is a gap between the basics of JavaScript, and what you need to understand coding in React. Not a massive gap, mind you, but enough of one that makes it worth exploring. And even if you’re not in to React, the concepts we’ll be going through should give you a more in-depth understanding of how JavaScript syntax works.

So let’s dive in to 7 elements of JavaScript you need to know to code with React, how they show up and how they can be useful to you.

Truthiness & Falsiness

A quick one before we start going into the more advanced stuff. There are some values in JavaScript that are considered to be falsy. That means that although they are not worth the boolean value false, they will still not trigger an if statement. JavaScript behaves as if these values were false, so we call the “falsy”.

There are several falsy values in JavaScript, this includes among others undefined, null, the empty string, an empty array, the number 0, and the value “not a number” (or NaN).

This is going to come in useful for when we start playing around with boolean operators and the ternary operator…

Boolean operators

You’re probably familiar with using the boolean operators &&and ||in conditions. But the way the syntax is built in JavaScript allows you to do a lot more than that. You see, these operators don’t necessarily return a boolean value.

Let’s start with the boolean or operator (||). This evaluates the first element of the expression, and looks at whether it is falsy or not. If the value is truthy, the operator returns the first value, if not, it returns the second one. So let’s imagine we have a variable (for example, name) and we don’t know whether it is set or not. If it is not set, we want to set a default value. The or operator allows us to do :

 let defaultedName = name || "defaultName"; 

Here, if name is undefined or null or an empty string, the operator will return the second term, the “defaultName” value. And if name is correctly defined, it will be returned by the operator. This allows us to set a default value.

The && boolean operator has exactly the opposite behaviour. If the first term is “truthy”, the && operator returns the second term. Let’s see how we can use this in React. For example, let’s imagine we have a variable called errorMessage, which might or might not contain an error message (depending on whether one has occurred or not).

In the JSX part of our code, in React, we can write something like this:

{error && <span>{error}</span>}

In this case, the && operator only returns the span if the errorvariable is truthy… which means we only show the <span>if there’s an error.

The ternary operator

In JavaScript (and in several other languages), there is a kind of condensed if / else statement called the ternary operator).

It works something like this, with a question mark and a colon:

variableTruthy ? itIsTrue : itIsFalse 

What the operator does is check if the variable is truthy. If it is, the operator return the first term after the question mark. If it is not, it returns the term after the colon. Going back to our error display, if we also want to show a message when there is no error, we can add the following to our JSX code:

{ error ? <span>{error}</span> : <span>"There is no error"</span>}

Of course in this specific case we could have written it more simply within the span :

<span>{error ? error : "There is no error"}</span>

… but only because I didn’t bother to add any styling to the span for the error.

Destructuring arrays and objects

Let’s look at a simple useState hook.

const [counter, setCounter] = useState(0);

Look at how the counter and setCounter variables are defined. They are defined from within an array. In reality, what is happening is we are mapping the variables to the return of useState. The hook returns an array, and this notation puts the first element of that array into counterand the second element into setCounter.

This is a shorter (and more elegant) way of writing :

 const temp = useState(0);
 const counter = temp[0];
 const setCounter = temp[1];

As you can see, the restructuring syntax is a lot more concise, and does away with the temporary variable. There is a similar syntax for objects, which usually shows up in the import statements, for example :

import { useState } from 'react';

For example, let’s say we have a user object with an age and a name

const user = {
  name: "Bob", 
  age: 42

We can retrieve a name directly using destructuring:

const {name} = user; 

This would amount to

const name = user.name;

The arrow function

The arrow function is a more concise way of writing functions. And in React, being concise helps write readable code. Arrow functions are also the natural way to write useEffect hooks. As a quick recap: the “normal” way of writing a function is to use the functionkeyword. e.g.:

function add(a,b) {
  return a + b;

We can write this as an arrow function by declaring :

const add = (a,b) => {
  return a + b;

In fact, as there is only a return statement in this function, we can do away with the brackets and the returnstatement itself :

 const add = (a,b) => a + b

This is useful in particular when using the array functions.

Array functions, in particular map and filter

Arrays have interesting functions that can operate on them. There are two in particular that I find especially useful in React: map and filter. Both these take a function as a parameter and return a new array.

Filter returns an array that only contains the items for which the function passed as a parameter returns a truthy value.

If we filter an array of numbers by the function that returns modulo 2, our new array now only contains odd numbers. This is because even numbers return 0 when run through modulo, and 0 is falsy:

const odd = [1, 2, 4, 7, 9, 22].filter((a) => a % 2);
// odd now only has odd numbers :  [1, 7, 9]

Map, on the other had, returns an array where each new item is the return value of the function. For example, if we pass in a function that multiplies the input argument by 2, the resulting output contains an array of the doubles of the initial array.

const double = [1, 2, 4, 7, 9, 22].map((a) => a * 2);
// double now has doubles:  [2, 4, 8, 14, 18, 44]

How is this useful in React? To take a basic example, let’s say we are building a to-do list application and have an array of tasks we want to display, stored in a tasksvariable. Let say each item has (for example) :

  • an ID,
  • a title,
  • a completed state, which can be true or false. Let’s also say we’ve defined a <Task> component, we can create a list by using the map function to return a task component for every item:
tasks.map((task) => <Task key={task.id} task={task} /> 

We can also show only incomplete items by using filter to hide the complete items :

tasks.filter(task => !item.complete).map((task) => <Task key={task.id} task={task} /> 

(As a small aside, it’s important to note here is that we need to specify a key value to help React track exactly what has changed.)

There are many other useful array functions worth mentioning, but these are the two that are the most useful in React.

The spread operator (and object property shorthand)

If you happen to start tracking the state of not just scalar values but also objects, you’ll need to start using the spread operator. The spread operator allows us to create a duplicate object with all the same values.

const user = {
  name: "Bob", 
  age: 42

const user1 = user; const user2 = {...user};

console.log(user == user1); // true console.log(user == user2); // false

Why is this useful? Well, React tracks changes to know when to re-render parts of the component tree. In the example above, user and user1 are the same object.

If we for example set the age property to 43 on user1, user1will still equal user.

Now, imagine React was tracking the state of the user object. Changing a value of one of the properties of the user object is not enough to trigger the detection of a state change. For example, let’s say we have a setUser function that is supposed to update the user state.

If we do:

user.age = 43;

This won’t be enough to trigger the change detection. We need to create a new object using the spread operator, and so do :

setUser({...user, age: 43});

Now what has happened here? The two curly brackets mean we’ve created a new object. The spread operator acts like it splits open (or spreads) the initial object. If we were to write what happens here explicitly, it would be long-winded. For example, we would first create a blank new object, and then list all the keys on the userobject. Then we iterate over the list of keys, and set the value of the key in the new object to the value in the old object. And then finally we would set the new changed value.

const newUser = {}
let keys = Object.keys(user); 

for(let i = 0; i < keys.length; i++) { let key = keys[i]; newUser[key] = user[key]; }

newUser.age = 43;

Kind of long-winded, right!

The spread operator condenses all that into one line, in a way that is just as readable (if not more) once you understand what it means.

Taking the next step

Finally, if you are also doing a lot of client/server interaction, it is also useful to understand how Promises and async/await work. It isn’t a fundamental part of React, and there are hooks that hide the complexity for you. But if you want to master JavaScript, it is unavoidable.

If you wish to master React, though, it’s even more important to understand how hooks work, and the beginner’s mistakes you need to avoid.

Made by kodaps · All rights reserved.
© 2023