JavaScript Basics for React.js: A Beginner's Guide

Krishna KumarKrishna Kumar
20 min read

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 a var 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 like let.

  • 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 a const 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:

  1. 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.

  2. 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:

  1. Arithmetic Operators:

    • + (addition)

    • - (subtraction)

    • * (multiplication)

    • / (division)

    • % (modulus)

    • ** (exponentiation)

  2. 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)

  3. Logical Operators:

    • && (logical AND)

    • || (logical OR)

    • ! (logical NOT)

  4. Assignment Operators:

    • = (assignment)

    • += (addition assignment)

    • -= (subtraction assignment)

    • *= (multiplication assignment)

    • /= (division assignment)

  5. Ternary (Conditional) Operator:

    • condition ? expressionIfTrue : expressionIfFalse

        const a = 5;
        const b = 10;
      
        const max = a > b ? a : b;
      
        console.log(max); // 10
      
  6. 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:

  1. 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
      
  2. 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])
        }
      
  3. 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 and reject.

  • 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! πŸš€πŸ¦Έβ€β™‚οΈπŸ‘¨β€πŸ’»

0
Subscribe to my newsletter

Read articles from Krishna Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Krishna Kumar
Krishna Kumar