So you've decided to learn React? Great! It's one of the most popular open-source JavaScript libraries out there that helps you build component-based interfaces.
If you're just starting with React having a basis of JavaScript foundation to work off of will help you a lot. If you've started learning React a while back but are finding it hard to grasp the concepts, this article will aim to build a solid foundation for your learning path into React.
We will dive into modern JavaScript techniques that will help you in your journey to becoming a React master.
Why I wrote this Article
When I was learning React, I dove right into it without really making sure that I have grasped the basics of JavaScript. After all, React is a JavaScript library. It is built on JavaScript, so it would make sense that having that solid foundation there would make your learning a lot easier.
I had used JavaScript in previous roles, so I wasn't completely new to it but hadn't gone fully into the details of it or refreshed my understanding of it. My most recent role was also very C# focused so a JavaScript refresher was needed. But being the eager beaver that I am, I rushed I dove right into React.
Looking back, this was probably a mistake and I would have been better off doing a quick refresher on modern JavaScript concepts before starting. It would have also made the barrier to entry for React much easier.
So hopefully, if you are reading this article, you're planning or are on your journey with React and this will help you avoid some of the pitfalls that I came across.
Let's get started.
Modern JavaScript Concepts You Should Know Before Learning ReactJS
React, and many other modern JavaScript frameworks and libraries are based on ES6 syntax. So the examples given below are all going to follow the ES6 syntax. You can still use ES5 syntax in your React code if you want to, but ES6 syntax makes things a lot easier.
1. Use Let and Const
Before ES6, the only way to create a variable was by using the var
keyword. let
and const
came out with ES6 as two new ways to create a variable in JavaScript.
These two keywords help keep the code we write more reliable and predictable. Let's dive into the differences between these two keywords a bit more.
What is var
?
var
keyword is used in the global scope or function scope. Scope refers to the locations these variables are available for use.
Scope of var
When var
is used outside of a function, it is then available in the global scope i.e. it is available for use in the whole window. When var
is used using inside of a function it is available only within that function.
Let's take a look at the following example:
var message = "Hello World";
function myFunction() {
var name = "My Name";
}
console.log(message); // Hello World
console.log(name); // error: name is not defined
Logging message works because it is globally scoped. Logging name variable fails because it is only accessible within the function called myFunction
.
Hoisting of var
Variables created using the var
keyword are also susceptible to hoisting in JavaScript. This means that the declarations are moved to the top of their scope before the code is executed. i.e. If we code the following:
console.log(myVariable);
var myVariable = "Hello World";
is interpreted to this:
var myVariable;
console.log(myVariable); //myVariable is undefined
myVariable = "Hello World";
The variable is hoisted to the top of the scope and initialised to undefined before it is used. This can cause some unexpected errors.
Re-declaring var
variables
Another thing to consider with var
variables is that they can be re-declared and updated.
That means the following is valid:
var message = "Hello World";
var message = "Hello World Again";
message = "I've changed";
This can potentially cause problems if you are unknowingly updating the message variable. For example:
var message = "Hello World";
if(true) {
var message = "My Name";
}
console.log(message); // My Name
If you are not aware that there is already a var
variable in the global scope with the same name, then you will overwrite it. And if this message variable is used elsewhere in the code then this could be problematic.
This is where let
and const
come in.
What is let
?
let
is now the prefered method of variable declaration in JavaScript because it comes with a few improvements. Let's go over the reasons why that is.
let
is block-scoped
let
variables are block-scoped. That means that they only live within the set of curly braces they are declared in. For example:
let myNumber = 4;
if (myNumber > 3) {
let myMessage = "Hello world";
console.log(myMessage);// "Hello world"
}
console.log(myMessage) // myMessage is not defined
If the let
variable is used outside the code block it is defined then it returns an error.
let
can be updated but not re-declared
Similar to var
, a let
variable can be updated later in the code. However, unlike var
, a let
variable can only be declared once within its scope. Which makes code more reliable and predictable. Let's look at an example:
let myMessage = "My name is Bob";
myMessage = "Hi Bob";
let greeting = "Welcome to my homepage";
let greeting = "What do you think?"; // error : Identifier 'greeting' has already been declared
let myNumber = 3;
if(true) {
let myNumber = 5;
console.log(myNumber); // 5
}
console.log(myNumber); // 3
As you can see from the above if the same let
variable is declared in the same scope an error is thrown. However, the same let
variable name can be declared in different scopes as they are treated as different variables.
This is why let
is better and safer to use than var
because it removes the worry of using the same variable name in the same scope.
Hoisting let
Similar to var
, a let
variable can be hoisted up. However, where var
variables are initialised to undefined, let
variables are not initialised. This eliminated the reference error
we encounter with var
.
What is const
?
const
variables share most of the properties of let
variables, with one main exception.
const
variables cannot be updated or re-declared
This means that any variable declared with the keyword const
remains the same within its scope. It cannot be updated or re-declared. For example, we cannot do the following:
let myMessage = "My name is Bob";
myMessage = "Hi Bob"; // error: Assignment to constant variable.
let greeting = "Welcome to my homepage";
let greeting = "What do you think?"; // error : Identifier 'greeting' has already been declared
Because of this, every const
variable declared must also be initialised at the same time.
One thing to note, however, is that if we are declaring a const
object, we cannot update the object but the properties of the object can be updated. Let's take a look:
const customer = {
name = "James",
age = 23
}
customer.name = "Robert";
console.log(customer.name); //Robert;
customer = {
isMember = true,
membershipNumber = 123
} // error: Assignment to constant variable.
As you can see, we can update the properties of a const
object but we cannot modify or add new properties to it.
Let's sum up the differences
var | let | const | |
Variable Scope | function | block | block |
Can be re-assigned | Yes | Yes | No |
So, the recommendation now is to not use var
and instead try and use const
as default, unless you need to re-assign your variables.
In React, the keyword const
is used to declare a functional component. We won't be reassigning the component, therefore it makes sense for it to be a const
. For example:
import React from "react";
const Welcome = () => <h1> Welcome to my Component </h1>
export default Welcome;
2. String Templating and concatenation in ES6
Before the release of ES6 we used to have to concatenate string in the following way:
var firstName = "Bob";
var lastName = "Marley";
var message = "Welcome" + " " + firstName + " " + lastName + " " + "to your homepage.";
console.log(message); // Welcome Bob Marley to your homepage.
This way of concatenating string is very error-prone, as you can imagine, and can be very difficult to read. With ES6 we now have template literals.
Template literals allow us to embed variables directly into our strings, and the compiler will formulate the correct final string. Simply use backticks instead of single or double quotes and use the $ sign along with curly braces to include the variables. Let's take a look at this in practice with the example we used above.
var firstName = "Bob";
var lastName = "Marley";
var message = `Welcome ${firstName} ${lastName} to your homepage.`;
console.log(message); // Welcome Bob Marley to your homepage.
As we can see this is a lot simpler and clearer syntax for concatenating strings. And this syntax fits right into the way of writing React.
3. Importing and exporting modules
React popularised component architecture. Modules/components are built up on top of each other to add functionality and various elements to the page.
JavaScript modules are created and exported to be used in your React application. When building your component hierarchy in React we import only the components we need. So understanding the concepts of importing and exporting in JavaScript is essential to becoming comfortable with React.
Let's look at an example we have used before:
import React from "react";
const Welcome = () => <h1> Welcome to my Component </h1>
export default Welcome;
We have now created a Welcome component that can be used in another component by importing it in.
import React from "react";
import Welcome from "./componenets/Welcome";
const myShop = () => {
return(
<div>
<h1>Today our shop is open</h1>
<Welcome />
</div>
)
}
4. Arrow functions
Using arrow functions in your React code will make your code much simpler and easier to read, but also will make you a quicker developer as there are fewer lines of code that you need when using this format when compared to standard functions. Arrow functions can also be used to create React components.
I'm not saying that you can't write React without using arrow functions, in fact, a lot of React code that you come across online will have class components and will also have a lot of standard functions in the codebase. Standard functions are still valid.
But, unlike standard functions, arrow functions do not have their own binding to the this
keyword within its definition. This makes it easier to use callbacks in arrow functions and means fewer bugs in code.
//Function expression
const add = function(int1, int2) {
return int1 + int2;
};
//Arrow function expression
const add = (int1, int2) => int1 + int2;
console.log(add(1, 2)); // 3
5. Destructuring
Introduced in ES6, destructuring will allow you to pull out properties from objects or items in an array into distinct values that can be used in your code.
How to use Destructuring?
Let’s take for example the following object:
const person = {
name = “Mike”,
age = 23,
favouriteColor = “Red”
}
Before ES6 came along we had to access each property of the object in the following way:
console.log(person.name) // Mike
console.log(person.age) // 23
console.log(person.favouriteColor) // Red
With destructuring, we can access the properties in a more streamlined way.
const { name, age, favouriteColor } = person;
This is the same as accessing each property of the object and assigning it to a variable of the same name.
With destructuring we can now use these new variables without the person.
prefix. E.g.
console.log(name) // Mike
How do we use Destructing in React?
In React, before using props that have been passed to your component you can destructure the props object. This is where this feature really shines.
Let’s take a look at the <Car />
component that we create below. We can pass it some props, for example, topSpeed
, make
, and color
. These can then be destructured and used in their own right.
const Car = ({ topSpeed, make, color}) => {
return (
<div>
<h1>{make}</h1>
<p>Top Speed of: {topSpeed}{/p>
<p>Color: {color}</p>
</div>
);
}
This can be taken further if there are objects being passed into the props of your component. You can also destructure the properties of those objects into variables of their own right. The following syntax is used myObject: { property1, property2 }
. This will give us access to both myObject
and the destructed properties to use within this component.
Let’s take a look at what destructuring looks like in a class component using the example we used above.
class Car extends React.Component {
render() {
const {topSpeed, make, color}
} = this.props;
return (
<div>
<h1>{make}</h1>
<p>Top Speed of: {topSpeed}{/p>
<p>Color: {color}</p>
</div>
) ;
}
Once we understand the concept behind destructuring and its benefits we can see how simple it is that can make our code more readable and clear and DRYer, especially when passing down props in React.
6. The spread Operator (…)
The spread operator is a clean way of including all elements of an object or an array. Almost like doing a foreach
loop. Let’s take a look:
const nums = [ 1, 2, 3 ];
console.log(...nums); \\ 1 2 3
In the above example, we take the array nums and pass all the values of the array, one by one, into the log function using the spread syntax and the array name.
The benefit of the spread syntax is that it is a shorthand syntax and also it is dynamic. That means that if the length of the array changes then the output would be updated accordingly. No matter how many elements are in the object or array, the log function will still work with the same value.
The spread operator is also very useful when adding new items to an array.
let numArray = [ 1, 2, 3 ];
let new = 4;
numArray = [...numArray, new];
console.log(...numArray); // 1 2 3 4
And also when combining two arrays:
let stringArray = [ 'One', 'two', 'Three' ];
stringArray = [ 'zero', ...stringArray, '4', 'five' ]; // will coming two arrays together.
console.log(stringArray); // zero One two Three 4 five
let arr1 = [ 1, 2, 3];
let arr2 = [ 4, 5];
arr1 = [ ...arr1, ...arr2 ];
console.log(arr1); // 1 2 3 4 5
One thing to note is that the spread operator will actually create a new arr1
and does not modify the original arr1
. This means that the original variables are not mutated.
Spread operators also allow us to clone objects by passing all the key-value pairs from one object to another.
let clone = { ...myObj }
One thing to note is that the spread syntax only does what is called a shallow copy. i.e. it goes only one level deep when copying an array. This is something to remember when trying to copy multi-dimensional arrays.
Overall, there are many benefits of using the spread operator, and these can all be applied to your React application. For example, destructuring pops:
<Modal {...this.props} >
And also for updating state:
this.setState(prevState => {
return {foo: {...prevState.foo, a: "updated"}};
});
The above will replace this.state.foo
with a new object of the same name and properties, except with the value of the a
property now set to "updated".
7. Filter
The filter
method does what it says on the tin. Use the filter
method to return all values in an array excluding ones that meet set criteria. Let's take a look:
const myArray = ['Bob', 'James', 'Sam'];
const nameToRemove = 'Sam';
const result = myArray.filter(nameCheck);
function nameCheck(name) {
return name !== 'Sam';
}
console.log(result); // Bob James
Simple right? A couple of things to note about the filter method:
- It creates a new array that only contains elements that have passed the criteria provided.
- It does not execute if the array being filtered is empty
- It does not change the original array
8. Map
The map
method also creates a new array by iterating through each element in the array and passing it to a provided function. The result is that inserted into a new array.
const myNums = [1, 2, 3];
const result = myNums.map(x => x * 5);
console.log(result); // [5, 10, 15]
If you aren't using the returned array then it is recommended to use forEach
instead as this is seen as an anti-pattern. i.e. the code will be doing more work than it needs to.
9. Classes
Classes are a very important concept in React, so having a good handle on this will go a long way in helping you succeed with React.
What are classes?
A class is a template for creating objects. It contains data and code that will work on that data.
This concept is the foundation behind React's component hierarchy. Each component is a class with specific functions and data requirements. Like building blocks of a bigger project.
This is useful because in practice we normally need to create many objects of the same kind. E.g. different types of cars.
By creating classes we can have the building blocks of a car, and simply pass it properties we want the car to have. For example:
class Car {
constructor(make, color, year, maxSpeed) {
this.make = make;
this.color = color;
this.year = year;
this.maxSpeed = maxSpeed;
}
}
Now that the class has been created I can now create a new car out of that class:
let familyCar = new Car("Audi", "Blue", "2018", 120);
let sportsCar = new Car("Ferrari", "Red", "2019", 260);
Methods can then be added to the class and used in the code. For example, let's add a method to our class to change the colour and get a paint job done.
Before the closing bracket of the class and after the closing bracket of the constructor let's add the following code:
getAPaintJob(newColor) {
this.color = newColor;
}
Now we can call the getAPaintJob
function and change the color of our cars to anything we want:
familyCar.getAPaintJob("Black");
console.log(familyCar.color); // Black
React uses this ES6 syntax for classes to build components:
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {
make: this.props.make,
color: this.props.color,
year: this.props.year,
topSpeed: this.props.topSpeed ,
};
}
render() {
return (
<div>
<h1>My {this.state.make}</h1>
<p>
Color: {this.state.color},
Top Speed: {this.state.topSpeed},
Year: {this.state.year}.
</p>
</div>
);
}
}
ReactDOM.render(
<Car
make="Audi"
color="Red"
year="2018"
topSpeed="120"
/>,
document.getElementById('container')
);
If you are familiar with Object Orientated Programming (OOP) then this concept of classes might be familiar to you.
As you can see classes can be very powerful tools. They help make your code more clean, maintainable and DRY. In my opinion, this is probably one of the most important concepts to grasp when learning React.
Takeway
I hope you found this article helpful. Please do let me know if you have any topics you would like me to write about next.
If you happen to have any tips about learning React yourself, whether you are a beginner or a React Ninja, I'd love to read them in the comments below!
Thanks, and see you in the next article.