Categories
reactjs

Demystifying Virtual DOM in React.js

DOM manipulation as we know is the most common operation that is used for performing dynamic interactions in a website. We grab references to certain DOM elements, then we might need to register listeners on the elements to listen for certain events and things like that. The problem here is that this DOM manipulation is a slow process and too much of DOM manipulation operations can bloat your application and this is because the JavaScript and its frameworks update the DOM quite frequently than they need to.

Let us understand this with the help of an example :

Consider a list of elements and let us say we want to delete the second item of that list. Now as we know most of the JavaScript frameworks that we have out there will rebuild the entire list which is of course more work than what needs to be done. So what happens here is that the entire list was made to rebuilt for just one deletion. So there is a huge overhead if we take into account the amount of DOM manipulation that goes into this. So to address this problem, the concept of Virtual DOM came into picture.

Virtual DOM

So let’s discuss about the virtual DOM that we discussed in the previous paragraph.

The virtual DOM is simply a virtual representation of the entire DOM.

So what happens here is that whenever any piece of our application state undergoes a change, that change is mapped to the virtual DOM instead of directly applying it to the real DOM. Now you may wonder, how come then it is faster than the real DOM. No worries, we are here to dive into the reasons as to why Virtual DOM is faster and efficient than the real DOM.

So for every DOM object we get a corresponding virtual DOM object. Both these objects have the same properties. Now here comes the main crux which is that manipulating the real DOM is a lot slower than the virtual DOM. So manipulating the virtual DOM is just like having a copy of the real DOM and performing changes on it before the same gets committed to the real DOM.

How it all works ?

So as we develop our UI, new elements get added to the DOM which in turn composes the entire DOM tree. Each element that we create is a node of this tree. Now if a piece of our application state experiences a change, then a new virtual DOM tree needs to be tree. This new tree that gets created is then made to undergo a comparison or in React terms we call this as “diffing” with the previous virtual DOM.

Next, once we are done with this step, computations regarding how these changes will be mapped to the real DOM are carried by the virtual DOM. The goal is to ensure that the updates can be made as fast as possible without interacting much with the real DOM and with as less operations as possible. The benefit of this in the end is to improvise on performance standpoint and thus reducing the cost of updating the real DOM.

Patching of changes from virtual DOM to real DOM

Now once the virtual DOM gets updated, React then compares the virtual DOM with the previous snapshot of the virtual DOM so basically the version of virtual DOM that existed before the update came into picture. With this comparison, React is able to figure out which parts of the virtual DOM underwent changes. This process is called as diffing which we also discussed above.

So to sum it up, once React has the knowledge of which virtual DOM objects have undergone a change, it simply updates those and only those objects on the real DOM. So for the example of our list, React simply updates the one item that was deleted without touching the other items of the list. This is what makes the entire difference in performance. So therefore this is how React can make sure that it updates only the relevant parts of the DOM.

Categories
reactjs

✨Top resources to learn React.js [in no particular order]

Hey everyone 👋🏻,

I recently wrote an article where I mentioned about React Projects Every Beginner Should Try : https://dev.to/thenerdydev/10-react-projects-every-beginner-should-try-fk9.

In this article, I will be mentioning the top 5 resources that I highly recommend if you want to learn React.js.

PS : I am not an affiliate of any of these resources/courses. These are just some of my personal recommendations if you are looking to learn React.

Introduction

Image description


React.js is a frontend JavaScript library for building amazing, sleek and performant user interfaces specifically for single page applications a.k.a SPAs. It is used for handling the view layer for web and mobile apps. React allows us to compose the entire user interface using the basic building blocks that are called as components.

Here are the top 5 recommendations (in no particular order) of the courses that you should definitely check out for learning React.

1. Build Web Apps with React & Firebase by Shaun Pelling a.k.a The Net Ninja (rated 4.8)

Image description

Shaun is a gifted teacher. He knows how to explain stuff in a very easy and lucid manner. This course will definitely take your knowledge to the next level if you are looking to learn this specific technology.

Here is what this course covers

Learn how to create modern & dynamic React websites from the ground up

Learn how to implement a database, authentication & file uploads with React & Firebase

Learn about Components, Props, Hooks, Context, State, Reducers & the React Router

Create & deploy fully fledged user-based React websites

Course Link :

https://www.udemy.com/course/build-web-apps-with-react-firebase/

2. React.js – The Complete Guide by Maximilian Schwarzmuller ( rated 4.6)

Image description

This course as the name can probably tell you covers the internals of React in great detail. The course starts from the very basics like What React.js is and how it works and later on moves to more complex and advanced topics

Here is what this course covers

A thorough introduction to React.js (What is it and why would you use it?)

All the core basics: How React works, building components with React & building UIs with React

Components, props & dynamic data binding

Working with user events and state to create interactive applications

A (thorough) look behind the scenes to understand how React works under the hood

Detailed explanations on how to work with lists and conditional content

React Hooks (in-depth)!

Working with built-in Hooks and building custom Hooks

How to debug React apps

Styling React apps with “Styled Components” and “CSS Modules”

Working with “Fragments” & “Portals”

Dealing with side effects

Class-based components and functional components

Sending Http requests & handling transitional states + responses

Handling forms and user input (incl. validation)

Redux & Redux Toolkit

Routing with React Router

An in-depth introduction into Next.js

Deploying React Apps

Implementing Authentication

Unit Tests

Combining React with TypeScript

Adding Animations

Tons of examples and demo projects so that you can apply all the things you learned in real projects

and more …

Course Link :

https://www.udemy.com/course/react-the-complete-guide-incl-redux/

3. Complete React Developer in 2022 (w/ Redux, Hooks, GraphQL)

Become a Senior React Developer! Build a massive E-commerce app with Redux, Hooks, GraphQL, ContextAPI, Stripe, Firebase. This course is created by two instructors – Andrei Neagoie and Yihua Zhang who have working experience with some of the best US Startups and big companies.

Image description

Here is what this course covers

React Basics

– React Router

– Redux

– Redux Saga

– Asynchronous Redux

– React Hooks

– Context API

– React Suspense + React Lazy

– Firebase

– Stripe API

– Styled-Components

– GraphQL

– Apollo

– PWAs

– React Performance

– React Design Patterns

– Testing with Jest, Enzyme and Snapshot testing

– React Best Practices

– Persistence + Session Storage

– State Normalization

Course Link :

https://www.udemy.com/course/complete-react-developer-zero-to-mastery

4. React.js Documentation (a must thing to refer)

Image description

Docs link :

https://reactjs.org/docs/getting-started.html

So this is it for this article. Thanks for reading.
Don’t forget to leave a like if you loved the article. Also share it with your friends and colleagues.

Categories
frontend javascript reactjs

Demystifying the useReducer Hook in 5 minutes

In this video, we will learn about a very important hook which is the useReducer hook.

Categories
frontend javascript reactjs

Demystifying the useEffect hook in under 13 minutes

In this video, we will learn about the useEffect hook in great detail and we will cover all the cases for the useEffect hook that one faces while working on a React app.

Categories
frontend javascript reactjs

Demystifying the useState hook in under 10 minutes

In this video, we will learn first about the basic Hooks that we have in React namely the useState and the useEffect hook. Once we understood the bare basics of the need for Hooks, then we will start to learn about the useState hook.

Categories
frontend javascript reactjs

Create your own Exercise Planner using React.js [Complete Code]

Hey everyone 👋🏻,

In this article, let us see how we can build an Exercise Planner Application using React.js.

✏ Demo for the Project & Initial Setup

So the first thing you need to do is to create a new project.
Make sure to install Node.js onto your system because we will be needing that for our project.

We will be using this tool for creating a new React Project :

Create React App :

image

Install Node.js :image

Create a new React Project

// To create a new React Project 
npx create-react-app <project_name>
cd <project_name>
// To run the project 
npm start

Install React Router DOM package

npm install react-router-dom 

Install JSON-server package globally

We will be using JSON-server for our project.

npm install json-server -g

Create a new file – exercises.json

This is the file that will contain all the exercises that we will be needing in this application. This file will serve as a local JSON store for our application.

store/data.json

{
  "exercises": [
    {
      "title": "Pushups",
      "details": "Pushups are beneficial for building upper body strength. They work the triceps, pectoral muscles, and shoulders. When done with proper form, they can also strengthen the lower back and core by engaging (pulling in) the abdominal muscles",
      "complete": false,
      "id": 119
    }
  ]
}

Inside a new terminal, run the json-server by running the command

json-server -g ./src/store/data.json --watch --port=3111

Complete Code 👨🏻‍💻

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

App.jsx

import {Switch, Route } from "react-router-dom"
import HomePage from './pages/HomePage';
import './App.css';
import CreateExercise from "./pages/CreateExercise";
import Navbar from "./components/Navbar";
import EditExercise from "./pages/EditExercise";

function App() {
  return (
    <div className="App">
      <Navbar />
      <Switch>
        <Route path="/home" exact>
          <HomePage />
        </Route>
        <Route path="/create-exercise" exact>
          <CreateExercise />
        </Route>
        <Route path="/exercises/:id/edit">
          <EditExercise />
        </Route>
      </Switch>
    </div>
  );
}

export default App;


App.css

.App {
  text-align: center;
}

index.css

html {
  --pink: #D60087;
  --golden: goldenrod;
  --green: rgba(216, 235, 48, 0.83);
  --text-shadow: 2px 2px 0 rgba(0,0,0,0.2);
  font-size: 62.5%;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  box-sizing: border-box;
}

*, *:before, *:after {
  box-sizing: inherit;
}

body {
  font-size: 2rem;
  line-height: 1.5;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:svgjs='http://svgjs.com/svgjs' width='1440' height='560' preserveAspectRatio='none' viewBox='0 0 1440 560'%3e%3cg mask='url(%26quot%3b%23SvgjsMask1000%26quot%3b)' fill='none'%3e%3crect width='1440' height='560' x='0' y='0' fill='%230e2a47'%3e%3c/rect%3e%3cpath d='M136.72 348.61a22.94 22.94 0 1 0 43.22-15.38z' stroke='%23e73635'%3e%3c/path%3e%3cpath d='M511.55 165.45L536.61 165.45L536.61 190.51L511.55 190.51z' stroke='%23037b0b'%3e%3c/path%3e%3cpath d='M483.33 455.66 a20.42 20.42 0 1 0 40.84 0 a20.42 20.42 0 1 0 -40.84 0z' fill='%23e73635'%3e%3c/path%3e%3cpath d='M1228-20.28a48.24 48.24 0 1 0-63.63 72.52z' stroke='%23037b0b'%3e%3c/path%3e%3cpath d='M1392.69 128.01 a29.96 29.96 0 1 0 59.92 0 a29.96 29.96 0 1 0 -59.92 0z' stroke='%23d3b714'%3e%3c/path%3e%3cpath d='M1076.84 554.49L1113.49 554.49L1113.49 591.14L1076.84 591.14z' stroke='%23d3b714'%3e%3c/path%3e%3cpath d='M756.26 7.46L795.56 7.46L795.56 35.82L756.26 35.82z' fill='%23d3b714'%3e%3c/path%3e%3cpath d='M25.99 370.04L26.54 370.04L26.54 423.32L25.99 423.32z' fill='%23d3b714'%3e%3c/path%3e%3cpath d='M905.99 522.28 a27.93 27.93 0 1 0 55.86 0 a27.93 27.93 0 1 0 -55.86 0z' stroke='%23d3b714'%3e%3c/path%3e%3cpath d='M878.82 241.19L928.56 241.19L928.56 290.93L878.82 290.93z' fill='%23e73635'%3e%3c/path%3e%3cpath d='M620.67 145.35L648.93 145.35L648.93 173.61L620.67 173.61z' stroke='%23037b0b'%3e%3c/path%3e%3cpath d='M941.34 228.22a0.43 0.43 0 1 0-0.84 0.22z' stroke='%23e73635'%3e%3c/path%3e%3cpath d='M142.87 85.55 a19.16 19.16 0 1 0 38.32 0 a19.16 19.16 0 1 0 -38.32 0z' stroke='%23037b0b'%3e%3c/path%3e%3cpath d='M329.59 523.81L381.54 523.81L381.54 575.76L329.59 575.76z' fill='%23e73635'%3e%3c/path%3e%3cpath d='M794.97 148.48 a17.04 17.04 0 1 0 34.08 0 a17.04 17.04 0 1 0 -34.08 0z' stroke='%23d3b714'%3e%3c/path%3e%3cpath d='M1144.93 501.44a3.73 3.73 0 1 0-6.24 4.09z' stroke='%23e73635'%3e%3c/path%3e%3cpath d='M1.85 326.79L6.52 326.79L6.52 331.46L1.85 331.46z' fill='%23d3b714'%3e%3c/path%3e%3cpath d='M1161.24 414.19L1165.88 414.19L1165.88 445.98L1161.24 445.98z' fill='%23e73635'%3e%3c/path%3e%3cpath d='M1208.54 452.49a10.52 10.52 0 1 0 10.48 18.25z' fill='%23e73635'%3e%3c/path%3e%3cpath d='M1356.2 405.97a49.06 49.06 0 1 0 59.45-78.06z' stroke='%23037b0b'%3e%3c/path%3e%3cpath d='M569.26 204.09 a47.56 47.56 0 1 0 95.12 0 a47.56 47.56 0 1 0 -95.12 0z' stroke='%23d3b714'%3e%3c/path%3e%3cpath d='M955.59 150.05a43.84 43.84 0 1 0-65.58-58.2z' stroke='%23e73635'%3e%3c/path%3e%3cpath d='M827.49 284.25L864.82 284.25L864.82 321.58L827.49 321.58z' stroke='%23d3b714'%3e%3c/path%3e%3cpath d='M718.92 539.64 a45.27 45.27 0 1 0 90.54 0 a45.27 45.27 0 1 0 -90.54 0z' fill='%23d3b714'%3e%3c/path%3e%3cpath d='M1253.87 200.13L1273.78 200.13L1273.78 220.04L1253.87 220.04z' fill='%23e73635'%3e%3c/path%3e%3cpath d='M365.3 8.63L376.7 8.63L376.7 16.04L365.3 16.04z' stroke='%23e73635'%3e%3c/path%3e%3cpath d='M691.18 292.33a16.5 16.5 0 1 0 0.63-33z' fill='%23037b0b'%3e%3c/path%3e%3cpath d='M224.16 500.66L270.06 500.66L270.06 546.56L224.16 546.56z' fill='%23e73635'%3e%3c/path%3e%3cpath d='M174.91 13.36 a25.6 25.6 0 1 0 51.2 0 a25.6 25.6 0 1 0 -51.2 0z' stroke='%23037b0b'%3e%3c/path%3e%3cpath d='M1396.28 502.2 a16.58 16.58 0 1 0 33.16 0 a16.58 16.58 0 1 0 -33.16 0z' fill='%23037b0b'%3e%3c/path%3e%3cpath d='M1337.35 217.49L1380.42 217.49L1380.42 268.22L1337.35 268.22z' fill='%23d3b714'%3e%3c/path%3e%3cpath d='M429.47 162.98a54.75 54.75 0 1 0 89.11 63.64z' fill='%23d3b714'%3e%3c/path%3e%3cpath d='M56.44 369.3L67.51 369.3L67.51 397.03L56.44 397.03z' stroke='%23e73635'%3e%3c/path%3e%3c/g%3e%3cdefs%3e%3cmask id='SvgjsMask1000'%3e%3crect width='1440' height='560' fill='white'%3e%3c/rect%3e%3c/mask%3e%3c/defs%3e%3c/svg%3e");

}
:focus {
  outline-color: var(--pink);
}

Components

components/BaseFilter.css

 .filter-nav button {
    background: none;
    border: none;
    color: #bbb;
    outline: none;
    font-size: 15px;
    text-transform: uppercase;
    margin-right: 10px;
    letter-spacing: 1px;
    font-weight: bold;
    cursor: pointer;
  }
  .filter-nav button.active {
    color: goldenrod;
  }

components/BaseFilter.jsx

import React from "react";
import './BaseFilter.css';
const BaseFilter = (props) => {

    <nav className="filter-nav">
      <button
        onClick={() => props.onUpdate('all')}
        className={props.current === 'all' ? 'active' : ''}
      >
        View all
      </button>

      <button
        onClick={() => props.onUpdate('completed')}
        className={props.current === 'completed' ? 'active' : ''}
      >
        Completed
      </button>

      <button
        onClick={() => props.onUpdate('pending')}
        className={props.current === 'pending' ? 'active' : ''}
      >
        Pending
      </button>
    </nav>
  );
};

export default BaseFilter;

components/ExerciseItem.jsx

import React from 'react'
import { Link } from 'react-router-dom';

import './ExerciseItem.css';

function ExerciseItem(props) {

  const performExerciseDeletion = () => {

    fetch(`http://localhost:3111/exercises/${props.exercise.id}`, {
      method: 'DELETE',
    })
      .then(() => props.onDeleteExercise(props.exercise.id))
      .catch((err) => console.log(err));

  };

  const performExerciseCompletion = () => {
    fetch(`http://localhost:3111/exercises/${props.exercise.id}`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ complete: !props.exercise.complete }),
    })
      .then(() => props.onCompleteExercise(props.exercise.id))
      .catch((err) => console.log(err));

  };
  const classes = ['exercise'];
  if (props.exercise.complete) {
    classes.push('complete');
  }
  return (
    <div className={classes.join(' ')}>
      <div className="actions">
        <h4>{props.exercise.title}</h4>
        <div className="buttons">
          <button onClick={performExerciseDeletion}>Delete</button>
          <Link to={`/exercises/${props.exercise.id}/edit`}>Edit</Link>
          <button onClick={performExerciseCompletion}>Toggle</button>
        </div>
      </div>
      <div className="details">
        <p>{props.exercise.details}</p>
      </div>
    </div>
  );
}

export default ExerciseItem;

components/ExerciseItem.css

.exercise {
  margin: 20px auto;
  background: white;
  padding: 10px 20px;
  border-radius: 10px;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
  border-left: 10px solid var(--pink);
}
.exercise:hover {
  box-shadow: 0 16px 32px 0 rgba(0,0,0,0.9);
}
h3 {
  cursor: pointer;
}
.actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.exercise.complete {
  border-left: 10px solid var(--green);
}
.buttons {
  display:flex;
  flex-direction: column;
}
.buttons button,a {
 color: white;
  background: var(--pink);
  padding: 0.5rem;
  border: 0;
  border: 2px solid transparent;
  text-decoration: none;
  font-weight: 600;
  font-size:2rem;
  margin-bottom: 5px;
   border-radius: 6px;

}
.buttons button:hover, a:hover, button:active, a:active {
  background: rgb(225, 127, 143);
}
h4 {
  transform: skew(-21deg);
  background: var(--golden)
}

components/ExercisesList.css

.exercises-list {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  max-width: 600px;
  margin: 0 auto;
  color: #555;
}

components/ExercisesList.jsx

import React from 'react'
import ExerciseItem from './ExerciseItem';
import './ExercisesList.css'

function ExercisesList(props) {

  if (props.exercises.length === 0) return null;

  return (
    <div className="exercises-list">
      {props.exercises.map((exercise) => (
        <ExerciseItem
          key={exercise.id}
          exercise={exercise}
          onCompleteExercise={props.onCompleteExercise}
          onDeleteExercise={props.onDeleteExercise}
        />
      ))}
    </div>
  );

}

export default ExercisesList;

components/Navbar.css

.main-nav {
    text-align: center;
    margin: 40px auto;
  }
  .main-nav a{
    display: inline-block;
    text-decoration: none;
    margin: 0 10px;
    color: goldenrod;
    font-size: 20px;

  }
  .active-style {
    border-bottom: 2px solid goldenrod;
    padding-bottom: 4px;
  }

components/Navbar.jsx

import React from 'react'
import './Navbar.css';
import { NavLink } from "react-router-dom";

function Navbar() {
  return (
     <nav className="main-nav">
      <NavLink activeClassName="active-style" to="/home">
        Home
      </NavLink>
      <NavLink activeClassName="active-style" to="/create-exercise">
        Create Exercise
      </NavLink>
     </nav>
  );
}

export default Navbar

Pages (Views)

Create a folder for pages where we will house all our page components.

pages/HomePage.jsx

import React, { useState, useEffect  } from 'react';
import BaseFilter from '../components/BaseFilter';
import ExercisesList from '../components/ExercisesList';

const HomePage = () => {
  const [exercises, setExercises] = useState([]);
  const [currentFilter, setCurrentFilter] = useState('all');

  const updateFilterHandler = (newFilter) => {
    setCurrentFilter(newFilter);
  };

  const deleteExerciseHandler = function (id) {
    const patchedExercises = exercises.filter((exercise) => exercise.id !== id);
    setExercises(patchedExercises);
  };

  const completeExerciseHandler = function (id) {
    const clonedExercises = [...exercises];
    const currentExerciseIndex = clonedExercises.findIndex(
      (exercise) => exercise.id === id
    );
    const currentExercise = clonedExercises[currentExerciseIndex];
    currentExercise.complete = !currentExercise.complete;
    setExercises(clonedExercises);
  };


  useEffect(() => {
      try {
        const response = await fetch('http://localhost:3111/exercises');
        const fetchedExercises = await response.json();
        console.log(fetchedExercises);
        setExercises(fetchedExercises);

      } catch (error) {

        console.log(error);
      }
    }

    fetchExercises();

  }, []);


  let jsx = (
    <ExercisesList
      exercises={exercises}
      onCompleteExercise={completeExerciseHandler}
      onDeleteExercise={deleteExerciseHandler}
    />
  );
  if (currentFilter === 'completed') {
    jsx = (
      <ExercisesList
        exercises={exercises.filter((exercise) => exercise.complete)}
        onCompleteExercise={completeExerciseHandler}
        onDeleteExercise={deleteExerciseHandler}
      />
    );
  } else if (currentFilter === 'pending') {
    jsx = (
      <ExercisesList
        exercises={exercises.filter((exercise) => !exercise.complete)}
        onCompleteExercise={completeExerciseHandler}
        onDeleteExercise={deleteExerciseHandler}
      />
    );
  }
  return (
    <div>
      <BaseFilter 
        onUpdate={updateFilterHandler} 
        current={currentFilter} />
      {jsx}
    </div>
  );
};

export default HomePage;

pages/CreateExercise.css

form  {
    padding: 20px;
    border-radius: 10px;
    text-align: center;
  }
  label {
    display: block;
    color: goldenrod;
    text-transform: uppercase;
    font-size: 14px;
    font-weight: bold;
    letter-spacing: 1px;
    margin: 20px 0 10px 0
  }
  input {
    padding: 10px;
    width: 400px;
    max-width: 100%;
    box-sizing: border-box;
    border: 1px solid var(--grey);
  }
  textarea {
    padding: 10px;
    max-width: 100%;
    width: 400px;
    box-sizing: border-box;
    border: 1px solid var(--grey);

  }
  form button {
    display: block;
    margin: 20px auto;
    background: goldenrod;
    color: white;
    padding: 10px;
    border-radius: 6px;
    font-size: 16px;
    border: 2px solid transparent;
  }

pages/CreateExercise.jsx

import React, { useState } from 'react';
import './CreateExercise.css';
import { useHistory } from 'react-router-dom';

const CreateExercise = () => {

  const [exercise, setExercise] = useState({
    title: '',
    details: ''
  })

  const history = useHistory();

  const handleChange = event => {
    setExercise({
      ...exercise,
      [event.target.name] : event.target.value
    });
  }

  const handleExerciseCreation = (event) => {

    event.preventDefault();

    const newExercise = {
      title: exercise.title,
      details : exercise.details,
      complete: false,
      id: Math.floor(Math.random() * 10000),
    };

    console.log(newExercise);

    fetch('http://localhost:3111/exercises', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(newExercise)
    }).then(() => {
      history.push('/home');
    }).catch(err => console.log(err))
  };

  return (
    <form  onSubmit={handleExerciseCreation}>
      <label>Title</label>
      <input type="text" onChange={handleChange} name="title" value={exercise.title} maxLength="15" required />
      <label>Details</label>
      <textarea value={exercise.details} name="details"  onChange={handleChange} required></textarea>
      <button>Add Exercise</button>
    </form>
  );
};

export default CreateExercise;

pages/EditExercise.jsx

import React, { useState, useEffect } from 'react';
import './CreateExercise.css';
import { useHistory, useParams } from 'react-router-dom';

const EditExercise = () => {

  const [exercise, setExercise] = useState({
    title: '',
    details: '',
  });

  const params = useParams();
  const exerciseId = params.id;
  const history = useHistory();

  const handleChange = (event) => {
    setExercise({
      ...exercise,
      [event.target.name]: event.target.value,
    });
  };

  useEffect(() => {

    fetch(`http://localhost:3111/exercises/${exerciseId}`)
      .then((res) => res.json())
      .then((data) => {
         setExercise({
           title: data.title,
           details: data.details,
         });
      })
      .catch((err) => console.log(err));

  }, [exerciseId])

  const handleExerciseUpdation = (event) => {

     event.preventDefault();
     fetch(`http://localhost:3111/exercises/${exerciseId}`, {
       method: 'PATCH',
       headers: { 'Content-Type': 'application/json' },
       body: JSON.stringify(exercise),
     })
       .then(() => {
         history.push('/home');
       }).catch((err) => console.log(err));
  };

  return (
    <form onSubmit={handleExerciseUpdation}>
      <label>Title</label>
      <input
        type="text"
        onChange={handleChange}
        name="title"
        value={exercise.title}
        maxLength="15"
        required
      />
      <label>Details</label>
      <textarea
        value={exercise.details}
        name="details"
        onChange={handleChange}
        required
      ></textarea>
      <button>Update Exercise</button>
    </form>
  );
};

export default EditExercise;

So this is the code for our entire project.

PS – If you prefer learning React with a video. I do have a video on same where we create this exact project.

Check this :

Thanks for reading !

Categories
frontend javascript reactjs

When to use the useRef hook ?

Hey everyone 👋🏻,

In this article, let us learn about a very special React Hook called as the useRef hook and understand how and when to use it.

What is the useRef hook ?

useRef hook is something that I briefly discussed in one of my articles where I described useRef hook as something equivalent to

Removing the state updating function from the useState, so basically just extracting the piece of state and take away the ability of state updation. This is something that will be equivalent to the useRef hook. I also discussed in that article that both the ref and state values persists across renders, so it is not the case that on every subsequent re-render they get set back to some default. So do make a note of the above points.

useRef is a React Hook which accepts a single argument as the initial default value and gives us something called as a ref. A ref is kind of an object that has a property called as current.

Let us see an example :

function SomeComponent() { 

    const usernameRef = React.useRef(''); 
    const handleSomething = () => { 
       console.log(usernameRef.currrent); 
       usernameRef.current = someOtherValue; 
    }
}

Now the things to note here is that usernameRef.current is used to access the value of the ref and if we want to update the ref value, then we can simply do so by setting usernameRef.current to a value of our choice.

To know more about refs, check my existing article on useRef hook. Here is the link for the same :

Image description

https://dev.to/thenerdydev/useref-hook-useref-vs-usestate-3i7k

In the above article, I have also taken some examples where I have demonstrated the usage of the useRef hook, we have discussed :

1. Ref Example – 1 (An Interval Timer)
2. Ref Example – 2 (Working with DOM using refs)
3. The third thing that we discussed in that article was :

useRef just like useState persists a value across renders but unlike useState it does not trigger a re-render of the component.

So in essence,

useRef = useState – state updating function

If you don’t know about the useState, no worries. You can learn about the same in this article :

https://dev.to/thenerdydev/react-hooks-demystifying-the-usestate-hook-in-under-10-minutes-examples-video-29ab

Let’s sum up what we learnt :

A ref is a plain JavaScript Object
{ current: <some_value> }

If you want to create a ref with the current value as null, then you can also make use of the createRef method,
React.createRef()

This gives us :
{ current: null }

Next, useRef(someInitialValue) also gives us a ref { current: someInitialValue }. The interesting thing about useRef is that it memoizes this ref so that it stays persistent across multiple renders of the component.

Another point to make a note of is that :

useRef(null) is basically equivalent to useState(React.createRef())[0]
But this kind of abuses the functionality.

Lastly, we learnt that useState causes a re-render in contrast to useRef. The state and the ref values (both) persist across re-renders.

So this is it for this article. Thanks for reading.

If you enjoy my articles, consider following me on Twitter for more interesting stuff :

Image description

⚡Twitter : https://twitter.com/The_Nerdy_Dev

Don’t forget to leave a like if you loved the article. Also share it with your friends and colleagues.

Categories
reactjs

Memoizing with React.useMemo

Hey everyone 👋🏻,

In this article, let us learn about a very special React Hook called as the useMemo hook and understand how and when to use it.

What is the useMemo hook ?

useMemo is a React Hook that was introduced to memoize expensive computations. Let us understand some basics about this. In order to understand the useMemo hook, let us understand its syntax:

const memoResult = useMemo(someFunction, dependencies);

So what happens with useMemo is that when the component renders for the first time, the useMemo hook invokes the someFunction (it could be any function, I am just calling it as someFunction) and memoizes the value that it computes for us and then it returns the result back to the component. Now the interesting thing here is that if during the subsequent renders, the list of dependencies that we specify do NOT change, then in that case useMemo will not invoke the someFunction but instead it will return the memoized value. Contrary to this, if the list of dependencies experience a change during subsequent renders, then useMemo will invoke the someFunction, memoize the result that it gets as a result of computation and then return it back to the component. So in essence, this is what happens in the useMemo hook.

Now let us see a simple example :

Let us say we have a component that deals with computation of factorial of a number, let’s call the component as FactorialResult. Now what this component does is that it computes the factorial of a number that is supplied into the input field by the user. Let us see the basic code for same :

import React from 'react' 
function computeFactorial(num) { 
   if(num == 0) { 
       return 1;
   }
   return num * computeFactorial(num - 1)
}
const FactorialResult = () => { 
  const [num, setNum] = React.useState(0); 
  const factorial = computeFactorial(num); 

  const handleChange = event => { 
         setNum(+event.target.value); 
  }
  return ( 
    <div>
      Factorial of 
      <input type="number" 
       value={num} 
       onChange={handleChange} />
      is {factorial}
    </div>

   );
}

Now every time, you change the input value, the factorial is re-calculated as a result of re-render.
Now how can we memoize this factorial calculation which itself is an expensive operation ? We want to memoize the factorial computation when the component re-renders. So for this we can make use of the useMemo hook. Let us make small changes in our code and memoize this factorial calculation. So here is the new code for the same component :

import React from 'react' 
function computeFactorial(num) { 
   if(num == 0) { 
       return 1;
   }
   return num * computeFactorial(num - 1)
}
const FactorialResult = () => { 
  const [num, setNum] = React.useState(0); 
  const factorial = React.useMemo(() => {
      computeFactorial(num)
   },[num]); 

  const handleChange = event => { 
         setNum(+event.target.value); 
  }
  return ( 
    <div>
      Factorial of 
      <input type="number" 
       value={num} 
       onChange={handleChange} />
      is {factorial}
    </div>

   );
}

Now every time you change the value of the num, the computeFactorial will get invoked but only if the num has changed. If num does not change on the re-render, then it will return the memoized result for its factorial and will not make that extra computeFactorial call. I hope that makes perfect sense.

Let’s see one more example to make the useMemo hook extremely clear.

Let us say we want to return the full name of a person, so for this let us say we have a function in some component that gives us the full name:

const fullName = React.useMemo(() => {
   return firstName + " " + lastName
},[firstName, lastName])

In above code, if the firstName or lastName change, then our fullName function will get re-invoked because we have specified firstName and lastName as dependencies. Please note : functions themselves usually don’t need to be re-computed, and their dependencies are mostly closure values that may change.

const fullName = React.useCallback(() => {
     return firstName + " " + lastName
}, [firstName, lastName]);

Now for above piece of code when firstName or lastName change, we don’t need a separate instance of the function on each re-render of the component, but we need exact the one and same instance of the function so that it has up to date values in the closure.

So this is it for this article. Thanks for reading.

Categories
reactjs

🐱‍👤When to use the useCallback hook ?

Hey everyone 👋🏻,

In this article, let us learn about a very special React Hook called as the useCallback hook and understand how and when to use it.

What is the useCallback hook ?

useCallback is a React Hook which was introduced to prevent re-creation of a specific function in case our component re-renders.
It does so by memoizing the callback function that this hook takes and this memoized version will only change when one of the inputs has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.

So typically we should make use of the useCallback hook in one of the following cases :

  1. If you are passing the function on to child component as props and the child component doesn’t often need re-rendering except when a certain prop change then useCallback might prevent certain re-renders.
  2. You are specifying a function as a dependency to useEffect. In such a case you must ensure that the function is not recreated on every render or the useEffect will be triggered on every render.

So in the essence, the decision to make use of the useCallback must be made judiciously instead of blindly since you might just overdo the advantage offered by useCallback and end up degrading the performance since useCallback will also memoize the functions and a frequently changing dependency might anyways need to recreate the function.

If the dependencies of the useCallback change, only then the function will get recreated otherwise it will use the exact one and the same instance of that function across the re-renders.

Example :

In JavaScript, we know that when a function gets executed we know that each and every thing (variables functions, objects etc) that is present within the function gets re-created into the memory. So this happens on each execution of the function. Now for a function we might not want it to get re-created on each re-render of the component and in turn we may want to use the exact same instance for that specific function in each of our renders. We might only want to re-create the function when a specific dependency which that function uses gets changed and NOT otherwise. This is something that we can achieve by making use of the useCallback hook.

Let’s see a simple Counter component.
Here we have a single piece of state which we call as counter and we have a corresponding state updating function for it which we named as setCounter. The initial value for counter is given as 0.
Next we have a handleIncrement counter function and all it does is that it increments the value of counter by 1.

const Counter = () => {
  const [counter, setCounter] = useState(0);

  const handleIncrement = () => {
    setCounter(counter + 1);
  }

  return <div>
    Counter:{counter}<br/>
    <button onClick={handleIncrement}>Increment</button>
  </div>
}

Now the interesting thing to note here is that the handleIncrement function will get re-created on each render of the component. This means that each time the component re-renders, handleIncrement function will get re-created at a separate spot in memory. And due to this reason, when React tries to make a referential equality comparison, it finds a change because of the re-creation of the handleIncrement function.

Now what if we wrap this with the useCallback hook ?

What the useCallback does is that it internally caches the first created version of the function and returns it to the caller if the listed dependencies haven’t changed. In case the listed dependencies does change, then it automatically gives us a new instance of that function.
So if we introduce the useCallback hook into our above code, then our code should look something like this :

const Counter = () => {
  const [counter, setCounter] = useState(0);

  const handleIncrement = React.useCallback(() => {
    setCounter(counter + 1);
  }, [])

  return <div>
    Counter:{counter}<br/>
    <button onClick={handleIncrement }>Increment</button>
  </div>
}

Now with the above code, what React will do is that it will cache the handleIncrement function internally and will make sure to return the exact same instance of the function in case no external dependencies of the useCallback have changed. In case, the external dependencies do change, then in that case a brand new instance of the handleIncrement function will get created for us. For our case, there are no external dependencies for the handleIncrement function.

Now caching the function internally by using the useCallback has its own cons. The cached instance of the function call will not have direct access to the variables of our current function call. Instead of that it will have visibility of the variables that were introduced in the initial closure call where the stored function was created. So in essence, this means that our call will not work for the updated variables. Therefore, we need to specify those variables or dependencies of the function that can change. The list of dependencies is to be passed as the second argument of the useCallback. In our example, we need to tell to useCallback function that we need a fresh version of our counter variable on each call. If we don’t do that, then the counter variable after the call will always be 1 and this is what comes from the original value 0 plus 1.

const Counter = () => {
  const [counter, setCounter] = useState(0);

  const handleIncrement = React.useCallback(() => {
    setCounter(counter + 1);
  }, [counter])

  return <div>
    Counter:{counter}<br/>
    <button onClick={handleIncrement}>Increment</button>
  </div>
}

The above version of code will not re-render on every call.

So this is it for this article. Thanks for reading.

If you enjoy my articles, consider following me on Twitter for more interesting stuff :

Image description

⚡Twitter : https://twitter.com/The_Nerdy_Dev

Don’t forget to leave a like if you loved the article. Also share it with your friends and colleagues.

Alt Text

Categories
javascript reactjs web development

React.js – How to use Refs in React.js

Using refs in React.js

Hey guys 👋🏻,
In this article, let us cover the topic of How to use Refs in React.js

Let us investigate why React.js, a library that keeps your code away from DOM manipulation, keeps its doors open for you to access. React rethinks a view as a result of a state of a component. It provides JSX, a syntactic sugar over JavaScript, to design the view layer and then modifies the DOM itself rather than giving the control to the developer.

Still, the React team provided escape routes and kept the library open for certain situations that go beyond the scope of what React is designed for.

Creating Refs

Refs are escape routes and it’s better to avoid them whenever possible. When we obtain a DOM element using ref and then later modify its attribute, we might enter into a conflict with React’s diff and update approach.

Let’s start with a simple component and grab a DOM element using ref, assuming that you already know how to set up a basic react app.

In the above piece of code, we are using a react hook useRef to create and initialize a variable called buttonRef. We then assign buttonRef to ref attribute on button JSX element.

Using React refs

As we discussed earlier in this article we are declaring views based on the state, and though we are still altering the state using functions, we are not in direct control of the DOM changes. But in a few use cases, it makes sense to introduce refs in your code.

Focus Control

To better understand the problem statement let’s storify the situation.

Alex is a software development intern at Metflix Inc. and his manager has given him the task of creating contact forms. The manager has asked him to focus on the first input element in the form when a modal is opened. Alex is confused about how he can achieve this in React.js. Let’s help Alex out.

The first thing we need to do is to get a reference to the input.

Next, when our modal loads, we imperatively call focus on our input ref.

Note: You need to access the element through the current property of the ref you declare.

Detect if an element is contained

Similarly, we would want to take an action in the app when an event is dispatched. Like close the modal when the user clicks outside of it.

Here, we are checking if the user click is out of the modalRef limit. If it is we are calling close() function from props to close the modal.

Integrating DOM-based libraries

Like React, there are other utilities and libraries outside its ecosystem that have been in use for years. To use such libraries, refs come in handy.

GreenSock library is a popular choice for animation examples. To use it, we need to send a DOM element to any of its methods.

Let’s go back to our modal and add some animation

Forwarding Refs

Refs are useful for specific actions. The examples shown are a little simpler than what we usually find in a real-life web application. We need to deal with complex components and we barely use plain HTML elements directly. It’s common to use a ref from one component in another component.

The issue now is that passing a ref to this component will return its instance, a React component reference, and not the input element we want to focus on like in our first example.

React provides forwardRef, which allows you to define internally what element the ref will point at.

Now, when a parent component passes a ref value, it’s going to obtain the input, which is helpful to avoid exposing the internals and properties of a component and breaking its encapsulation.

So this is it for this article. Thanks for reading.

If you enjoy my articles, consider following me on Twitter for more interesting stuff :

⚡Twitter : https://twitter.com/The_Nerdy_Dev

Don’t forget to leave a like if you loved the article. Also share it with your friends and colleagues.

Alt Text