Welcome to the world of mastering JavaScript for React.js development. Picture JavaScript as your loyal mentor, guiding you through the developer's journey, and React as your incredible superpower amplifier. Just as every superhero needs a mentor, you need JavaScript as an indispensable companion on the path to becoming a proficient web developer.
Are you ready to embark on this tech adventure? Whether you're a rookie or just need a quick refresher, this blog is your go-to toolkit for JavaScript brilliance.
Getting Started
So Let's brush up on some basics of JavaScript. If you're new to JavaScript, you can start with the basics. If you're already familiar with the basics, you can skip ahead to the next section.
What is JavaScript?
JavaScript is a programming language that allows you to implement complex features on web pages. Every time a web page does more than just sit there and display static information for you to look at, it is using JavaScript to do so.
What can JavaScript do?
JavaScript is a scripting language that enables you to create dynamically updating content, control multimedia, animate images, and pretty much everything else. It is the third layer of the layer cake of standard web technologies.
The first layer is HTML, which provides the structure of the page.
The second layer is CSS, which we use to add styling to the page.
The third layer is JavaScript, which we use to add functionality to the page.
Why do we need JavaScript for React.js?
React is a JavaScript library, so we need to know JavaScript to use React. React is a library for building user interfaces, which comprise only one part of an app. React is not a framework (unlike Angular, which is more opinionated).
How to use JavaScript React.js?
Now that you know what JavaScript is and why we need it for React.js, let's dive into the basics of JavaScript. We'll start with the basics and then move on to more advanced topics.
Syntax Essentials
Comments
There are 2 types of comments we can use in javascript
Single-line comments using
//
.// let a = 10; const b = 20; // value of b is 20
Multi-line comments using
/* ... */
./** * @param {number} a * @param {number} b * @return {number} * @description Add two numbers * You can add more comments here. */ function add(a,b){ return a+b; }
Variables
Variables are containers for storing data values. In JavaScript, we use the var/let/const
keyword to declare variables. A variable must have a unique name. You can assign a value to a variable using the = operator.
var a = 5;
let b = 10;
const c = 15;
Now we know how to declare a variable but we used 3 keywords, what is the difference? Let's find out.
var
, let
, and const
are used to declare variables in JavaScript. However, they have different use cases and behaviours:
var
Variables declared with
var
are function-scoped, meaning they are accessible throughout the entire function in which they are defined.Variables declared with
var
are hoisted to the top of their function or global scope during the compilation phase. This means you can use avar
variable before it's declared in the code, but it will have an undefined value.var
allows variables to be redeclared within the same scope.
if (true) {
var a = 10;
}
console.log(a); // 10 (accessible outside the if block)
var b = 20;
var b = 30;
console.log(b); // 30 (b can be reassigned because it's declared with var)
console.log(c) // undefined (hoisted but not initialized yet)
var c = 40;
c = 50;
console.log(d) // 50 (hoisted and initialized)
var c = 40;
Variables declared with var
are hoisted to the top of their scope during the compilation phase. This can lead to situations where a variable is used before it's declared, resulting in code that is harder to understand and debug. let
and const
does not exhibit this behaviour, so variables are not accessible before their declaration.
I recommend not using
var
unless required.
let
Variables declared with
let
are block-scoped, which means they are only accessible within the block (enclosed by curly braces) in which they are defined.let
variables are not hoisted to the top of their scope, so they are not accessible before the declaration.let
allows you to reassign values to variables, but it prevents redeclaration in the same scope.
if (true) {
let a = 10;
}
console.log(y); // ReferenceError: y is not defined (outside the block)
let b = 20;
b = 30;
console.log(b); // 30
const
Variables declared with
const
are also block-scoped, just likelet
.const
variables are not hoisted.Variables declared with
const
must be assigned an initial value when declared, and they cannot be reassigned once a value is assigned. However, the value of aconst
object or array can be modified (e.g., adding or removing elements), but you cannot change the reference to a different object or array.
const z = 10;
z = 20; // Error - cannot be reassigned
const obj = { prop: 'value' };
obj.prop = 'new value'; // Valid
obj = { prop: 'another value' }; // Error - cannot reassign the object
Data Types
Data types in JavaScript categorize values into various groups, determining how values behave and interact with each other. JavaScript has two main categories of data types:
Primitive Data Types
Number: Represents both integers and floating-point numbers. Examples:
5
,3.14
.String: Represents textual data enclosed in single or double quotes. Examples:
'Hello'
,"World"
.Boolean: Represents true or false values. Examples:
true
,false
.Undefined: Represents a variable that has been declared but not assigned a value.
Null: Represents the intentional absence of any object value.
Complex Data Types
Object: Represents a collection of key-value pairs. Objects can contain functions and other objects.
Array: Represents an ordered list of values, accessible by index. Example:
[1, 2, 3]
.Function: A callable object that can execute a block of code when invoked.
Date: Represents date and time values.
RegExp: Represents regular expressions for pattern matching in strings.
Map: Represents a collection of key-value pairs with better performance and additional methods.
Set: Represents a collection of unique values, helpful for filtering out duplicates.
Operators
Operators in JavaScript are symbols or keywords used to perform operations on values or variables. They enable you to manipulate data and make decisions in your code. Here's an overview of key operator categories:
Arithmetic Operators:
+
(addition)-
(subtraction)*
(multiplication)/
(division)%
(modulus)**
(exponentiation)
Comparison Operators:
==
(equality) (try to avoid)===
(strict equality)!=
(inequality) (try to avoid)!==
(strict inequality)>
(greater than)<
(less than)>=
(greater than or equal to)<=
(less than or equal to)
Logical Operators:
&&
(logical AND)||
(logical OR)!
(logical NOT)
Assignment Operators:
=
(assignment)+=
(addition assignment)-=
(subtraction assignment)*=
(multiplication assignment)/=
(division assignment)
Ternary (Conditional) Operator:
condition ? expressionIfTrue : expressionIfFalse
const a = 5; const b = 10; const max = a > b ? a : b; console.log(max); // 10
Type Operators:
typeof
(returns the data type of a value)console.log(typeof {name: "Krishna"}); // object console.log(typeof 5); // number console.log(typeof true); // boolean console.log(typeof "Krishna"); // string console.log(typeof undefined); // undefined console.log(typeof null); // object console.log(typeof function () {}); // function console.log(typeof []); // object console.log(typeof new Date()); // object console.log(typeof new RegExp()); // object console.log(typeof NaN); // number
instanceof
(checks if an object is an instance of a specific constructor)console.log({name: "Krishna"} instanceof Object); // true console.log(5 instanceof Number); // false console.log(true instanceof Boolean); // false console.log("Krishna" instanceof String); // false console.log(undefined instanceof undefined); // TypeError console.log(null instanceof null); // TypeError console.log(function () {} instanceof Function); // true console.log([] instanceof Array); // true console.log(new Date() instanceof Date); // true console.log(new RegExp() instanceof RegExp); // true console.log(NaN instanceof Number); // false
Control Structures
Control structures in JavaScript are constructs that determine the flow of your code. They allow you to make decisions and execute code conditionally or in a loop. Key control structures include:
Conditional Statements:
if
,else if
,else
: Execute code based on a specified condition.const a = "dog" if (a==="cat"){ console.log("it's a cat"); }else if (a==="dog"){ console.log("it's a dog"); }else{ console.log("Unknown"); }
switch
,case
,default
: Choose between multiple code blocks based on a given value.const a = 5 let day; switch(a) { case 0: day = "Sunday"; break; case 1: day = "Monday"; break; case 2: day = "Tuesday"; break; case 3: day = "Wednesday"; break; case 4: day = "Thursday"; break; case 5: day = "Friday"; break; case 6: day = "Saturday"; default: day = "Unknown"; } console.log(day) // Friday
Loops:
for
: Repeatedly execute code for a specified number of iterations.for (let i = 0; i < 10; i++) { console.log(i) }
while
: Execute code as long as a condition is true.let i = 0; while(i < 10){ console.log(i); i++; }
do...while
: Execute code at least once, then continue as long as a condition is true.let i = 0; do{ console.log(i); i++; } while(i < 10);
for...of
(ES6): Iterate over elements of an iterable (e.g., an array).const post = { title: "JavaScript", published: true, views: 100, } const keys = Object.keys(post) for (const key of keys) { console.log(key, post[key]) }
for...in
: Iterate over the properties of an object.const colors = ['red', 'green', 'blue'] for (const index in colors) { console.log(index, colors[index]) }
Branching and Jumping:
break
: Exit a loop or switch statement.for (var i = 0; i < 10; i++) { if (i === 5) { break; // stops the loop when i===5 } console.log(i); }
continue
: Skip the current iteration of a loop and continue with the next one.for (var i = 0; i < 10; i++) { if (i === 5) { continue; } console.log(i); // 5 will be skipped }
return
: Exit a function and return a value.function hello() { var a = 10; if (a === 10) { return; // stop the function } console.log("Hello"); } function square(a) { return a*a; // return the value of a*a }
Closures
Closures are a fundamental concept in JavaScript and refer to the ability of a function to access variables from its outer (enclosing) function, even after the outer function has completed execution. Key points to understand about closures:
A closure "closes over" the variables it needs, meaning it retains access to those variables even if the outer function has finished.
Closures are created whenever a function is defined within another function.
Closures are often used to encapsulate data and behaviour, allowing for information hiding and the creation of private variables.
They are a powerful tool for managing and controlling access to data, enabling the creation of modular and reusable code.
function outerFunction(outerVar) { // Inner function defined inside the outer function function innerFunction() { console.log(outerVar); // innerFunction has access to outerVar } // Return the inner function return innerFunction; } // Create a closure by invoking outerFunction const closure = outerFunction("I am from the outer function"); // Call the closure closure(); // Prints "I am from the outer function"
ES6 Magic
ES6, or ECMAScript 2015, is a significant update to the JavaScript language and brought several "magical" improvements that make coding in JavaScript more enjoyable and productive. Here are some of the notable "magical" features of ES6:
Arrow Functions
Arrow functions provide a concise syntax for defining functions, making code cleaner and more readable, especially for short functions.
// ES5
function add(x, y) {
return x + y;
}
// ES6
const add = (x, y) => x + y;
Template Literals
Template literals allow for more expressive and multiline string interpolation.
const name = "Krishna";
// ES5
var msg1 = "Hello, " + name + "!\nHow are you today?";
// ES6
const msg2 = `Hello, ${name}!
How are you today?`;
Let and Const
We learned about let
and const
which introduced block-scoped variable declarations, offering better control and predictability.
Destructuring
Destructuring simplifies the extraction of values from arrays and objects. It is a very important topic that will be often used in React.
// Destructuring arrays
const arr = [1, 2, 3, 4, 5];
// The destructuring syntax is [x, y] = arr.
// It means that we want to extract the first
// two elements from the arr array and assign
// them to the x and y variables.
const [x, y] = arr;
console.log(x); // 1
console.log(y); // 2
const [a,b,c,d,e] = arr;
console.log(a,b,c,d,e) // 1 2 3 4 5
// Destructuring objects
const obj = { first: "Krishna", last: "Kumar" };
// The destructuring syntax is {first, last} = obj.
// It means that we want to extract the first and
// last properties from the obj object and assign
// them to the first and last variables.
const { first, last } = obj;
console.log(first); // Krishna
console.log(last); // Kumar
const { first: f, last: l } = obj;
console.log(f); // Krishna
console.log(l); // Kumar
Spread and Rest Operators
The spread and rest operators make it easier to work with arrays and function arguments.
// Spread Operator
const numbers = [1, 2, 3];
const mergedWrong = [numbers, 4, 5];
const merged = [...numbers, 4, 5];
console.log(mergedWrong) // [[1, 2, 3], 4, 5]
console.log(merged) // [1, 2, 3, 4, 5]
// Rest Operator
function sum(...args) {
return args.reduce((total, num) => total + num, 0);
}
Classes
ES6 introduced a class syntax for defining and working with objects, making it more familiar to developers from other programming languages.
class Person {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, my name is ${this.name}`);
}
}
const krishna = new Person("Krishna");
krishna.sayHello(); // Hello, my name is Krishna
Promises
Promises provide a more structured way to work with asynchronous operations, simplifying error handling and improving code readability.
const promise = new Promise((resolve, reject) => {
// wait for 2000ms then run the function.
setTimeout(() => {
resolve("Success!");
}, 2000);
}).then((value) => { // after 2000ms the `then` statement will get the value from `resolve`.
console.log(value);
});
Flow:
1st we create a promise that gives us 2 arguments
resolve
andreject
.resolve
is used when we want to return a successful value.reject
is used when we want to return a failed value.We use
setTimeout
to simulate an asynchronous operation.After 2 seconds, we call resolve with the value Success.
We use .then() to get the value from the promise and then log the value to the console.
If you didn't understand it, don't worry; we will cover this in more detail in a later section.
Default Parameters
In ES6, users can provide the default values right in the signature of the functions. But, in ES5, the OR operator ||
had to be used.
// ES5
function add(a = 0,b = 0){
return (a || 0) + (b || 0);
}
// ES6
function add(a = 0,b = 0){ // default value to 0
return a+b;
}
console.log(add()); // 0
console.log(add(0,2)); // 2
Modules
ES6 introduced a standardized module system, allowing for better code organization and reuse. Previously we used the module.exports/require
keyword but now we have the import/export
that we can use.
// lib.js
function add(a, b) {
return a + b;
}
const lang = "Javascript"
const num = 21
module.exports = { add, lang, num }; // ES5
export { add, lang, num } // ES6
// main.js
// ES5
const lib = require('./lib.js');
console.log(lib.add(), lib.lang, lib.num)
const { add, lang, num } = require('./lib.js');
console.log(add(), lang, num)
// ES6
import lib from "./lib.js";
console.log(lib.add(), lib.lang, lib.num)
import { add, lang, num } from "./lib.js";
console.log(add(), lang, num)
Functions
In JavaScript, functions are a fundamental part of the language, and there are various ways to define and use them. Let's learn more about functions and the different ways to write them.
// Function Declarations (hoisted)
function greet(name) {
return `Hello, ${name}!`;
}
// Function Expressions (not hoisted)
const add = function(x, y) {
return x + y;
};
// Anonymous function expression
// No need to have a name
<button
onClick={function(a,b){
return a + b;
}}
>add</button>
// Arrow Functions
const multiply = (a, b) => {
return a * b;
}
const multiply = (a, b) => a * b;
// Anonymous Arrow Functions
<button
onClick={(a,b) => a + b}
>add</button>
// Generator Functions
// Special functions that can be paused and resumed
// They use the yield keyword to pause execution and can produce a sequence of values.
function* countUpTo(n) {
for (let i = 1; i <= n; i++) {
yield i;
}
}
const countTo5 = countUpTo(5);
console.log(countTo5.next()); // { value: 1, done: false }
console.log(countTo5.next()); // { value: 2, done: false }
console.log(countTo5.next()); // { value: 3, done: false }
console.log(countTo5.next()); // { value: 4, done: false }
console.log(countTo5.next()); // { value: 5, done: false }
console.log(countTo5.next()); // { value: undefined, done: true }
// Method Functions
const person = {
name: "Krishna",
greet: function() {
return `Hello, my name is ${this.name}.`;
}
};
console.log(person.greet()); // Hello, my name is Krishna.
// Immediately Invoked Function Expressions (IIFE)
(function() {
console.log("HEYY"); // Self Invoking
})();
Objects
Everything in JavaScript is an object.
Objects are collections of key-value pairs. Each key (also called a property) is a string, and it's associated with a value. Keys are unique within an object. We can access object values using dot notation (e.g., object.key
) or square bracket notation (e.g., object['key']
).
const person = {
name: "Krishna",
age: 21,
greet1: function() {
return `Hello, my name is ${this.name}.`;
},
greet2: () => {
return `Hello, my name is ${this.name}.`;
},
location: {
country: "India"
}
};
console.log(person.name); // Krishna
console.log(person["age"]); // 21
console.log(person.greet1()); // Hello, my name is Krishna.
console.log(person.greet2()); // Hello, my name is undefined.
console.log(person.location.country); // India
console.log(person["location"].country); // India
console.log(person.location["country"]); // India
DOM Manipulation
DOM (Document Object Model) manipulation is a core aspect of web development, allowing us to interact with and update web pages. DOM manipulation in React is very different from vanilla JavaScript.
In Vanilla JavaScript :
<!DOCTYPE html>
<html>
<body>
<div id="example">This is some text.</div>
<button onclick="changeText()">Change Text</button>
<script>
function changeText() {
const element = document.getElementById("example");
element.textContent = "Text has been changed!";
}
</script>
</body>
</html>
React Alternative :
import React, { useState } from "react";
function App() {
const [text, setText] = useState("This is some text");
const changeText = () => {
setText("Text has been changed!");
};
return (
<div>
<div>{text}</div>
<button onClick={changeText}>Change Text</button>
</div>
);
}
export default App;
React provides us with hooks that we can use to manipulate the DOM. Here in this example, we used useState Hook to store and change the value of the text. We can directly put the value of the text in the HTML using the variable surrounded by "{}". Let's see one more example.
Vanilla JavaScript :
<!DOCTYPE html>
<html>
<body>
<div id="box">This is a box.</div>
<button onclick="changeColor()">Change Color</button>
<script>
function changeColor() {
const element = document.getElementById("box");
element.style.backgroundColor = "blue";
}
</script>
</body>
</html>
React Alternative :
import React, { useState } from "react";
function App() {
const [backgroundColor, setBackgroundColor] = useState("white");
const changeColor = () => {
setBackgroundColor("blue");
};
return (
<div style={{ backgroundColor }}>
This is a box.
<button onClick={changeColor}>Change Color</button>
</div>
);
}
export default App;
In vanilla JavaScript, we selected the element using document.getElementById() then we updated the colour by updating the value of element.style.backgroundColor
key to "blue". In react we used the same useState() hook to store and change the backgroundColor. Here we named our value to backgroundColor which is the same as the name of the key in the style, then we used the function setBackgroundColor to change the colour.
<div style={{ backgroundColor }}>
<!-- same as: -->
<div style={{
"backgroundColor": backgroundColor
}}>
Also, notice in vanilla JS we used onclick whereas in React we used onClick Event Attribute. In React, all DOM properties and attributes (including event handlers) should be camelCased.
Asynchronous JavaScript
Asynchronous JavaScript is a programming paradigm that allows JavaScript code to run without blocking the main thread. This is useful for long-running tasks, such as making HTTP requests or reading files, as it allows the application to remain responsive while the task is running.
Let's see an example of an Async Function in React.
import { useState } from "react";
const AsyncFunctionExample = () => {
const [data, setData] = useState([]);
const fetchData = async () => {
// We can only use await inside an async function.
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts?_limit=5"
);
const resData = await response.json();
setData(resData);
};
return (
<div>
<button onClick={fetchData}>Fetch Data</button>
{data.map((item) => (
<div key={item.id}>
<h1>{item.title}</h1>
<p>{item.body}</p>
</div>
))}
</div>
);
};
export default AsyncFunctionExample;
In this example, we created an async function that fetches fake posts when clicked on the button and shows them on the page. we added an await before fetch so the JavaScript engine pauses execution of the async function until the awaited promise is resolved.
Error Handling
Let's do some error handling in the function we just created.
import { useState } from "react";
const AsyncFunctionExample = () => {
const [data, setData] = useState([]);
const [error, setError] = useState(null);
const fetchData = async () => {
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts?_limit=5"
);
const resData = await response.json();
setData(resData);
} catch (error) {
setError(error.message);
}
};
return (
<div>
<button onClick={fetchData}>Fetch Data</button>
{data.map((item) => (
<div key={item.id}>
<h1>{item.title}</h1>
<p>{item.body}</p>
</div>
))}
{error && <p>{error}</p>}
</div>
);
};
export default AsyncFunctionExample;
By adding a simple try-catch block we can handle the errors. Here I used the useState hook to store the error message and show if any error occurs. You can also use a toast/alert to show the error message.
JSX
Now that you have seen the React codes, let's deep dive into how to write JSX in React.
JSX stands for JavaScript XML. It is a syntax extension to JavaScript that makes it easier to write HTML-like markup in React. JSX is compiled into regular JavaScript code, so it is efficient and performant.
Note: All JSX elements must be closed. Self-closing tags like
<img>
must become<img />
, and wrapping tags like<li>
must be written as<li>oranges</li>
.
// Component name / Function
const ReactComponent = () => {
// All the rest of the codes/logic goes here
// ...
// Return HTML
return (
<div>
<h1>React Component</h1>
<p>This is basic HTML</p>
</div>
);
};
// React components should be exported so that
// we can use them in different files.
export default ReactComponent;
A basic React component has an extension of ".jsx" or ".tsx" for typescript. It exports a function that returns HTML. Remember component name which is also the function name should always start with a capital letter.
Variables
const ReactComponent = () => {
const name = "Krishna Kumar"
return (
<div>
// we can use variable in html directly by
// wrapping them inside {}.
<h1>{name}</h1>
</div>
);
};
export default ReactComponent;
Props
// User.jsx
const User = (props) => {
return (
<div>
<img
src={props.avatarUrl}
alt="user image"
/>
<h1>{props.name}</h1>
<p>{props.age}</p>
<p>{props.phone}</p>
</div>
);
};
export default User;
// App.js
import User from "./User"
const App = () => {
return (
<div>
// using the User Component by passing the props
// so it can fill it in the details.
<User
name="Krishna Kumar"
age={25}
phone="+91 9999999999"
avatarUrl="https://github.com/krishna8421.png"
/>
</div>
);
};
export default App;
This is a basic example of data passing down to components. You can pass strings, numbers, objects, functions etc.
Conditional Rendering
Sometimes you want a specific condition to be true like the user logged in or the user has permission to open a page for this, we use conditional rendering.
const ReactComponent = () => {
const isLoggedIn = true;
// return if user is Logged in.
if (isLoggedIn) {
return (
<div>
<h1>Welcome</h1>
<p>User is Logged In</p>
</div>
);
}
// If user is not logged in then show this
// message.
return (
<div>
<p>Hey you are not Logged In</p>
</div>
);
};
export default ReactComponent;
Sometimes we want to show data if it is present else some placeholder.
const ReactComponent = ({name}) => {
return (
<div>{ name ? <h1>Hi, {name}</h1> : <h1>Hi, Stranger</h1> }</div>
);
};
export default ReactComponent;
Here we destructured the props and got the name variable. Then in the div, we checked whether the name was present or null/undefined
, if present then <h1>Hi, {name}</h1>
will displayed else <h1>Hi, Stranger</h1>
.
Conclusion
As you wrap up this adventure, remember that JavaScript is your mentor in the world of web development, and mastering it is your path to becoming a coding superhero. Stay tuned for our next adventure, where we'll create a simple Todo App using React.js and see how these JavaScript skills combine with React to give you incredible superpowers in the web development universe. Keep coding, and let's unlock your coding potential together! ππ¦ΈββοΈπ¨βπ»