All The Javascript Concepts You Need To Know Before Learning React (Part 2)
Mark Jaily Peña
Posted on July 4, 2024
After a short break, thorough understanding, and countless hours of thinking. Here is the continuation of All The Javascript Concepts You Need To Know Before Learning React (Part 1) article I made a while ago. These concepts will act as a bridge towards learning React. Without further ado, let's delve into this article.
6. Understanding DOM
The Document Object Model, or DOM for short, is the representation of a web page. It has a tree-like structure where each node represents an individual HTML element. The DOM can be manipulated using JavaScript to create dynamic content and change or add elements, attributes, and styles. Performance-wise, direct DOM manipulation can be a problem, especially for complex applications, as you need to grab the nodes and apply changes to them manually, and the browser needs to re-render frequently, causing inefficiency and difficulty in managing.
Virtual DOM
React has its own kind of DOM called Virtual DOM, which is a virtual representation of UI that is synced with the "real" DOM. Virtual DOM finds the minimal set of changes needed to update the real DOM. This approach reduces the number of re-renders and improves efficiency.
You don't need to understand everything fully, but this gives you an idea of why React is popular
7. Async Await and Promises
Normally, everything is synchronous when you code in Javascript, meaning the execution is line by line.
let message = "Hello World";
console.log(message);
The first line of code is executed, declaring and initializing the message variable, and when it is done, the next line will print the message in the terminal or console.
But sometimes, there is a need for non-synchronous activity. Fetching from API is a common example of this. Fetching data from API may not always be instantaneous. Factors involving your internet connection, the size of your request, and how far you are from the server come into play.
const picturesOfCats = fetch("https://api.thecatapi.com/v1/images/search?limit=5")
console.log(picturesOfCats);
Also, that is a real API for getting data about cats :> Check out The Cat API. Not sponsored btw.
Here, we are fetching pictures of cats from an API and attempting to print those data. However, we will encounter something strange.
This is the result of console.log(picturesOfCats);
. So what is this Promise { <pending> }
?
Promises
Promises in JavaScript are objects used to deal with asynchronous operations. They represent a value that may be available now, in the future, or never.
const myPromise = new Promise((resolve, reject) => {
const success = true; // Simulate success or failure
if (success) {
resolve("The operation was successful!"); // Call resolve if the operation is successful
} else {
reject("The operation failed."); // Call reject if the operation fails
}
});
In this very simplistic example, we have a variable containing a promise.
This Promise
will take on a function with two arguments: resolve and reject. And inside the function, we can write logic to define this Promise
.
If you are confused, that's okay. Most of the time, we will not create our own promises. We will just use promises that are returned and deal with them.
resolve
is a function we call if the promise is successful, while the reject
is a function we call if the promise is unsuccessful. But how do we determine what resolve
and reject
are?
myPromise.then((result) => {
console.log(result); // Handle the successful result
}).catch((error) => {
console.error(error); // Handle the error
});
We will use the .then()
and .catch()
for those. .then()
is a function that will be called if we're resolved, and .catch
is a function that will be called if we're rejected. If the promise is resolved, we will see "The operation was successful!"
that came from the result
variable that was passed from the resolve()
and if not, we will see "The operation failed."
that came from the error
variable that was passed from the reject()
.
When making API requests, we will only use
.then()
and.catch()
most of the time, meaning when the request is made,.then()
we will do something, and if there are errors in the request, then we are going to.catch()
that errors.
There is also a finally
case where it will be called regardless of whether the promise is resolved or rejected.
myPromise.then((result) => {
console.log(result); // Handle the successful result
}).catch((error) => {
console.error(error); // Handle the error
}).finally(() => {
console.log("Promise Finished") // Will be called regardless if resolve or reject
});
Returning to the code that results in Promise { <pending> }
. Fetching data from API is asynchronous, but the program is synchronous, so the pending promise is getting printed because the fetch returns a Promise
instead of the actual data.
Fetching Data
const fetchCatPictures = () => {
const picturesOfCats = fetch("https://api.thecatapi.com/v1/images/search?limit=5")
picturesOfCats
.then(response => {
return response.json()
})
.then(data => {
console.log(data); // log the data when the Promise resolves
})
.catch(error => {
console.error("Error fetching data:", error); // handle any errors
}).finally(() => {
console.log("This is the end of the request");
});
};
// Call the function
fetchCatPictures();
Here is an example of fetching data from an API. Here, if the promise is resolved successfully, it returns a Response
object. This Response
object represents the HTTP response from the server. To extract meaningful data from this response, we need to parse it using the json()
method.
Async + Await
There is actually a different approach for fetching and waiting data, which uses async
+ await
, which allows JavaScript to wait for asynchronous operations to complete sequentially.
const fetchCatPictures = async () => {
try {
const response = await fetch("https://api.thecatapi.com/v1/images/search?limit=5");
const data = await response.json();
console.log(data); // log the data when the Promise resolves
} catch (error) {
console.error("Error fetching data:", error); // handle any errors
} finally {
console.log("This is the end of the request");
}
};
// Call the async function
fetchCatPictures();
In this code snippet, we convert the code that uses .then()
with async
+ await
. async
is used to declare asynchronous functions which return promises. It also allows await
keyword to be used inside that function. await
is used to pause the execution of an async
function until a Promise is settled.
Basically,
async
is needed to useawait
. Also,await
waits for the fetch to be done, then we can do something with the data after.
To handle errors when fetching data, we use the try-catch
block, and for the .finally(),
we just replace it with finally.
In a
try-catch
block, we basically try some codes, and if there are errors, then those will be caught by thecatch
.
Both .then()
method chaining and async
+ await
are fundamentally the same because async
+ await
is syntactic sugar that simplifies working with promises. This syntax allows for a more synchronous style of writing asynchronous code, which enhances readability. Both approaches are equally valid for handling asynchronous operations in JavaScript.
Other Ways Of Fetching Data From API
There are many ways to fetch data from an API. We can use the fetch()
like the codes above or use Javascript libraries such as Axios.
First, you need to install Axios if you haven't already. You can do this using npm or yarn:
npm install axios
or with yarn:
yarn add axios
Make sure you add
"type": "module"
in yourpackage.json
or if you don't have one, you can put.mjs
on your file instead of.js
.
const axios = require("axios"); // Import Axios (use `import axios from "axios"` if using ES modules)
const fetchCatPictures = async () => {
try {
const response = await axios.get("https://api.thecatapi.com/v1/images/search?limit=5");
console.log("Data fetched successfully:", response.data);
} catch (error) {
console.error("Error fetching data:", error);
}
};
// Call the async function
fetchCatPictures();
Note: The new way of importing in Javascript uses the
import
keyword, just like in my previous article. But the old wayrequire
can still be used. For more info, check out this article.Also, Axios offers numerous features, including direct access to the data property from the response, which is already parsed as a JSON object. This eliminates the need for manually invoking
.json()
, making data handling more convenient.
8. Optional Chaining
The optional chaining ?.
operator prevents errors when trying to access properties or call methods on null
or undefined
values. If a reference is null
or undefined
, the expression will return undefined
instead of throwing an error. When used with function calls, it returns undefined
if the specified function does not exist.
const student = {
name: "Mark",
age: 19,
address: {
city: "Davao City",
country: "Philippines"
}
}
const studentSchool = student.school?.name;
console.log(studentSchool); // Expected output: undefined
console.log(student.someNonExistentMethod?.()); // Expected output: undefined
In this example, we are trying to get the values of nonexistent property and method, which will throw an error, but with the optional chaining ?.
operator, it will only result in an undefined value.
In React or even plain Javascript, when fetching and dealing with data, sometimes your app can break when you are not specific with the data you are receiving or dealing with. Similarly above, if you are trying to access fields inside objects where those fields don't exist, your application will break.
const fetchData = async () => {
const data = await fetch("exampleapi.com");
const name = data.student?.name
}
Here, assuming we are fetching data from an imaginary API, and student
property may or may not exist. We can prevent breaking our app by using optional chaining ?.
operator. This ensures safely accessing properties and calling methods on objects that may have nullish values.
The optional chaining
?.
operator also helps to simplify code because there is no need for verbose conditional checks (if
statements or ternary?
operators).
9. Template Literals
Template literals are very useful, especially in React. They are string literals that allow embedded expressions and multiline strings. They are enclosed by backticks instead of single or double quotes, making creating complex strings with dynamic content easier.
It seems I cannot show backticks in this platform as backticks are reserved for markup, but they are usually located below the Esc Key.
const fetchData = async (animalName) => {
const data = await fetch("exampleapi.com/searchitem=" + animalName);
};
In this simple code snippet, assuming that we can add a search term, we can do something like this where we concatenate the API link with the argument containing our desired animalName
using +
operator. The API can send back pictures of animals or, in this case, cats.
const fetchData = async (animalName) => {
const data = await fetch(`exampleapi.com/searchitem=${animalName}`);
};
However, we can also use a template literal by replacing the quotes with backticks and adding ${}
. This makes it much more readable and easier to manage, especially when constructing complex strings with dynamic content.
Basically, you can now add Javascript inside your strings :>
I hope you were able to grasp the concepts of both my articles. This article is a little bit shorter than the first, but it still contains important concepts for you to learn. With this, you will have an advantage when transitioning from Javascript to React. Before I conclude this article, I would like to show an inspiring quote from my references.
Sometimes, overpreparing will hold you down and prevent you from actually progressing.
Just learn the essentials and don't delve too deep, as JavaScript and React are two separate coding experiences.
Happy Coding!
I will probably delve into backend soon. Anyways, thanks for reading!
References:
https://www.youtube.com/watch?v=ACaT1Gfhe6I
Posted on July 4, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.