Important Topics from React & JavaScript

React Hooks

React hooks allow us to reuse stateful logic without changing the component hierarchy. Hoooks let us use more react's features without classes.

State Hook

useState() is similar to this.setState in a class, except it doesn't merge the old and new state together.

import React, { useState } from "react"

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}

Effect Hook

useEffect() is used to handle the side effects (data fetching, subscriptions, or changing the DOM). Because these side effects can affect other components and can't be done during rendering.

By default, react runs the effects after every ender - including the first render.

Effects is also used to clean up after unmount of a component.

import React, { useState, useEffect } from "react"

export function EffectExample() {
  const [count, setCount] = useState(0)

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`
  }, [count]) // Only re-run the effect if count changes

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>
        Click me
      </button>
    </div>
  )
}

Rules of Hooks

  1. Only Call Hooks at the Top Level
  2. Don’t call Hooks inside loops, conditions, or nested functions.
  3. If we want to run an effect conditionally, we can put that condition inside our Hook:
  4. Only Call Hooks from React Functions
  5. Don’t call Hooks from regular JavaScript functions.
import React, { useState, useEffect } from "react"

export function FormHooks() {
  // 1. Use the name state variable
  const [name, setName] = useState("Mary")

  // 2. Use an effect for persisting the form
  useEffect(function persistForm() {
    localStorage.setItem("formData", name)
  })

  // 3. Use the surname state variable
  const [surname, setSurname] = useState("Poppins")

  // 4. Use an effect for updating the title
  useEffect(function updateTitle() {
    document.title = name + " " + surname
  })

  return <div></div>
}

Accessibility

Web accessibility (also known as a11y) support is necessary to allow assistive technology to interpret web pages.

React supports building accessible websites, by using standard HTML techniques.

Whereas most DOM properties and attributes in React are camelCased, aria-* HTML attributes should be kebab-cased as they are in plain HTML.

<input type="text" aria-label={labelText} />

Global Context

In the global context, this refers to the global object. In browser, the global context is window. In node.js, global context is global.

// In a browser:
console.log(this === window) // true

// In node:
console.log(this === global) // true

Function Context

Inside a function, the value of this depends on how the function is called.

In non-strict mode, if the value of this is not set, this will default to the global object.

function f() {
  return this
}

// In a browser
f() === window // true

// In Node:
f() === global // true

In strict mode, if the value of this is not set, this will be undefined.

function f() {
  "use strict"
  return this
}

f() === undefined // true

To set value of this to a particular value when calling a function, use call(), or apply()

Object Methods

An object method uses this to refer to the properties of the object.

const address = {
  name: "Foyez",
  city: "Cumilla",

  describe() {
    console.log(`I'm ${this.name} from ${this.city}`)
  },
}

address.describe() // I'm Foyez from Cumilla

Class Context

Note: Static methods are not properties of this. They are properties of the class itself.

Arrow functions

call() & apply()

call and apply are very similar. The both method call a function with a given this value and can pass optional arguments. The only difference is, call requires the arguments to be provided individually (one-by-one), and apply takes the arguments as an array (or an array-like object).

In this example, we'll create an object, and a function that references this but has no this context. However, we can use call and apply to invoke the this context of address on the function.

const address = {
  name: "Foyez",
  city: "Cumilla",

  getAddress() {
    console.log(`I live in beautiful ${this.city}.`)
  },
}

function summary() {
  console.log(`I'm ${this.name} from ${this.city}.`)
}

function longSummary(occupation, food) {
  console.log(
    `I'm ${this.name} from ${this.city}. I'm a/an ${occupation}. I love ${food}.`
  )
}

summary() // I'm undefined from undefined
summary.call(address) // I'm Foyez from Cumilla
summary.apply(address) // I'm Foyez from Cumilla

const getAddress = address.getAddress
getAddress() // I live in beautiful undefined.
getAddress.call(address) // I live in beautiful Cumilla.

longSummary.call(address, "student", "mango") // I'm Foyez from Cumilla. I'm a/an student. I love mango.
longSummary.apply(address, ["student", "mango"]) // I'm Foyez from Cumilla. I'm a/an student. I love mango.

To set the value of this to a particular value when calling a function, use call(), or apply() as in the examples below.

bind()

The bind() method creates a new function with an explicitly bound this.

bind() method is used in place of call() and apply() when we need to use the function bounded with this over and over.

const address = {
  name: "Foyez",
  city: "Cumilla",

  getCity: function () {
    return this.city
  },
}

function summary() {
  console.log(`I'm ${this.name}. I'm from ${this.getCity()}.`)
}

const unboundGetCity = address.getCity
console.log(unboundGetCity()) // undefined

const boundGetCity = unboundGetCity.bind(address)
console.log(boundGetCity()) // Cumilla

const boundedSummary = summary.bind(address)
boundedSummary() // I'm Foyez. I'm from Cumilla.