Categories
frontend javascript web development

JavaScript methods for finding elements

Hey guys,

Welcome back to a new article !

In this article, we will learn about different JavaScript methods that we can make use of for finding elements in an array. Arrays, as we know, is a data structure that is one of the key building blocks that we make use of for building data-based intensive web applications. With an array, we can easily store and manipulate elements within the array as and how we want to. Let us see the 4 methods that you can make use of for finding an element in an array.


find

The find() method returns the first element in the provided array that satisfies the provided testing function. So we specify a testing function as the callback and the find method will return the first item that returns true for the condition that we test within the specified callback. If no elements satisfy the testing function, then undefined gets returned. Let us see an example for the find method.

const numbers = [5, 12, 8, 130, 44];

const firstNumberGreaterThan10 = numbers.find(element => element > 10);

console.log(firstNumberGreaterThan10 );
// expected output: 12

findIndex

The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. So as a testing function, we pass a callback to the findIndex method and there we explicitly mention a condition and based on the truthiness of that condition, we get an element that satisfies that specified condition. In case, no element passes the testing condition then it returns -1.

const numbers = [1, 3, 4, 6, 10];

const greaterIndex = numbers.findIndex(element => element > 6); 
console.log(greaterIndex); // 4

const smallerIndex = numbers.findIndex(element => element > 10); 
console.log(smallerIndex); // -1 

Consider the above example in which we have a list of numbers that is given to us, let us say we want to find the index of the first occurrence of an element which is greater than 6. So for this case, we can make use of the findIndex method with the testing condition as element > 6. Next, let us say we want to find the index of the first occurrence of an element which is greater than 10. So we again make use of the findIndex method with the testing condition as element > 10. Now since there is no element that satisfies the above condition, hence we get a -1 for this.


indexOf

The indexOf() method returns the index of the first occurrence of the substring or element that we specify as the argument.

Let us see an example for the indexOf method, let us say we are given an array of elements and we want to find the index of some elements within that array. So see the below code :

const numbers = [1, 3, 4, 6, 10];

const indexOf10 = numbers.indexOf(10); // 4

const indexOf16 = numbers.indexOf(16); // -1

So if we try to search the index of the number 10 in the given array of numbers, then we get 4 because 10 is sitting at index 4 of the given array. Next, for the number 16 we get -1 because the number 16 is not present anywhere within the given array.


lastIndexOf

The lastIndexOf() method returns the index of the last occurrence of the specified substring or element that we specify as argument. The lastIndexOf method is similar to the indexOf method that we just discussed but the only difference being that it starts to look up from the trailing end of the array instead of the start of the array like we do in indexOf. So in essence, if you know for sure that the element that you are looking for lies in the latter half of the array, then using the lastIndexOf method makes more sense.

const numbers = [1, 3, 4, 6, 10];

const indexOf10FromLast = numbers.lastIndexOf(10); 

console.log(indexOf10FromLast); // 4

const indexOf16FromLast = numbers.lastIndexOf(16); 

console.log(indexOf16FromLast); // -1

So in above example, if we try to find the index of the last occurrence of a particular element, say 10, then we get 4. Since, 10 is present at index 4 and we only have one occurrence of 10 in the numbers array. Next, 16 is not present anywhere in the array so for that if we try to find the last occurrence of it using the lastIndexOf method, we get -1.


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

Categories
javascript

A Quick Refresher on Scopes in JavaScript – Function Scope, Global Scope and Block Scope

In this video, we will do a basic refresher on Scopes in JavaScript before we proceed further with more advanced topics in JavaScript. We will first talk about the Global Scope in JavaScript along with Function Scopes where we use the var keyword. Then we will move further and talk about the block scope in JavaScript that uses the modern ES6 introduced let and const keywords.

Follow me on:
👉 Twitter: https://twitter.com/The_Nerdy_Dev
👉 Instagram: https://instagram.com/thenerdydev

Categories
javascript

How Hoisting works in JavaScript ?

What is Hoisting in JavaScript?

JavaScript Hoisting refers to the process whereby the interpreter appears to move the declaration of functions, variables or classes to the top of their scope, prior to execution of the code.

Hoisting allows functions to be safely used in code before they are declared.

Variable and class declarations are also hoisted, so they too can be referenced before they are declared. Note that doing so can lead to unexpected errors, and is not generally recommended.

Hoisting is JavaScript’s default behavior of moving declarations to the top.

However there is a big misconception among developers regarding this concept of hoisting.

Now as a JavaScript developer, it is super important for you to truly understand the concept of hoisting not only because it will give you a better understanding of the language but also because this is one of the most important concepts that can easily award or cost you some points in interview rounds of a web development interview.

Let us see an example to understand more about hoisting
logUsername();
console.log(username); 

// define the username variable 
var username = "Alex";
function logUsername() { 
   console.log(username);
   console.log('logged...');
}

Here is what we get as the output for the above code :

HOW JAVASCRIPT WORK UNDER THE HOOD ?

When the JavaScript Engine goes over your code, it parses it and simply analyze it, it creates something called as the Execution Context. So this execution context is kind of a wrapper around your currently running code. It comprises of the global variable, the this object (you may know it as the this keyword) and the lexical variable environment of that execution context. Let us see an example first and then we will understand the concept of Hoisting in these examples using the Execution Context:

var num = 10;

function foobar() {
  console.log("function foobar is called!")
}

foobar();
console.log(num);

If we execute the above code, we get the following output :

Now what will happen if we move the last 2 lines of code in the beginning like this ?

foobar();
console.log(num);

var num = 10;

function foobar() {
  console.log("function foobar is called!")
}

We will get the following output if we run the above code :

Ideally for this case we would expect JavaScript to raise an exception because the function foobar is getting called right before it is declared and the variable num  is getting referenced before its declaration.

In this case if we see the output, the function foobar is getting executed even though we called it way before its declaration point and for the variable num we are getting an undefined. This simply means that JavaScript has access to the the foobar function and the num variable which is stored somewhere. Now in order to understand this, we need to understand the phases of execution context in JavaScript :

Execution Context comprises of two phases:

  1. CREATION PHASE:

During the creation phase of the execution context, JavaScript performs memory space allocation for the functions and the variables that we define. In case of functions, the whole function body gets stored but in case of the variables, it is declared and assigned a default value of undefined. This entire thing is also termed as Hoisting in JavaScript.

An important thing to understand is, the value of num is set to undefined during this phase because JavaScript in this case finds a variable num defined somewhere in our above code. If we remove the line var num = 10 then it will result in an error 

Uncaught ReferenceError: num is not defined.

So in the above when JavaScript ran console.log(num),  the var num is not assigned any value at that point so it picked up the value from the memory space which is set to undefined during the creation phase and printed that value.

As a side note, it is recommended not to rely on hoisting, that means it is a good practice to declare and define the variables and the functions before they are referred.

2. EXECUTION PHASE:

In this phase, JavaScript executes our code line by line and assigns the value to all our variables. In our above example, a value of 10 is assigned to the variable num

To understand this, let us have a look at the below code :

function foobar() {
  console.log("function foobar is called!")
}
foobar()
console.log(num);
var num = 10;
console.log(a)

Since we now understand the different phases of Execution, we can easily say by looking at the above code that the output of our code should be :

  • The function foo gets called and it prints the following message to the console : function foobar is called!
  • Now on the next line as we know that during the creation phase, JavaScript assigns a default value of undefined to the num variable. So this gives undefined as output.
  • The last line logs 10. Now the reason for getting 10 here is that in the execution phase, assignment of variable happened and num got the value of 10

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
javascript

JavaScript – toLowerCase and toUpperCase methods

Hey guys,
I am back with a new article. In this article, let us learn about simple methods that have in JavaScript using which we can convert a given string to its uppercase and its lowercase representation respectively. So without a further ado, let’s get started.

Introduction

So we have the JavaScript’s toLowerCase method that returns a string without any uppercase letters. Similarly, we have the toUpperCase method which returns us a string representation of the given string without any lowercase letters. So essentially both these methods take a string and convert it into a different representation.

Now when you are working with a string in JavaScript, you may encounter a situation where you feel the need to convert the case of a string. For example, if you’re creating a sign-up form that collects the username of a user, then you may want the email address to appear in all lowercase.
That’s where these methods (toLowerCase and toUpperCase) comes in. These methods allow us to convert a string to all lowercase and all uppercase, respectively.

In this article, we’ll explore how to use the toUpperCase() and toLowerCase() string methods in JavaScript. We’ll also walk through an example that demonstrates the usage of each of these methods.

Case Sensitivity in Strings

Now strings, as we know, represents a sequence of characters that joined together. Strings can include things like letters, symbols, numbers, and white spaces.

In JavaScript, we can declare strings using three types of quotes :

  1. Single Quotes (”)
  2. Double Quotes (“”)
  3. Backticks (“)

Single and double quotes can be used interchangeably, although you should keep your usage of either of these in a consistent manner throughout your program.

So let us take an example of a string in JavaScript :

Image description

Strings are case sensitive. What does this mean ? This means that when we compare strings, or when we search through strings, or otherwise manipulate them, the case of each individual character will make no impact on how we work with the string. So for example, if we compare two strings in different cases, the strings will not be considered the same by JavaScript.

toUpperCase method

So first we have the toUpperCase method that converts a string to uppercase letters. toUpperCase does not change the value of a string, instead it takes a copy of the string, mutate that by converting each character of that copied string into its uppercase form and then eventually return that instead of returning the original string.

Let us see the syntax for the toUpperCase method. So let us convert our username to its uppercase representation :

Image description

The toUpperCase method as you can see from the above example does not take any argument. It is just applied as a method on the string that we want to transform so basically using the dot operator. This then returns us a copy of the string with all characters in uppercase.

toLowerCase method

The toLowerCase method converts a given string into its lowercase representation. Like the toUpperCase method, it does not alter the original string. Instead, it simply makes a copy of the original string and mutate that so basically converting each of the given characters of the string into its lowercase representations.

Let us see the syntax of toLowerCase method in action

Image description


This toLowerCase method instead turns the string into its lowercase representation.

Conclusion

In this guide, we discussed how we can make use of the toUpperCase and toLowerCase method to convert a string to all-uppercase and all-lowercase, respectively.

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

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
backend database frontend javascript mongodb web development

New FULL Web Developer Course on YouTube

I decided to create a full Web Developer Course that will cover all the technologies that you need to kickstart your Full Stack Developer Journey. No bullshit, everything practical and relevant will be covered.

We will delve into following topics –

  1. HTML
  2. CSS
  3. JavaScript
  4. Node.js
  5. MongoDB

Check out the first video of this series where we cover the introduction to World Wide Web and the Evolution of the World Wide Web. The code for the video (if any) can be found on GitHub.

⭐ Check out the 10 JavaScript Projects in 2 Hours Video of my JavaScript Series where we build 12+ Projects using JavaScript :

Follow me on:
👉 Twitter: https://twitter.com/The_Nerdy_Dev
👉 Instagram: https://instagram.com/thenerdydev

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
javascript

Arrow Functions vs Normal Functions

Hey everyone 👋🏻,
In this article, let us understand the differences between Arrow Functions and Normal Functions.

Arrow Functions vs Normal Functions

We know that we can define JavaScript functions in many ways:

  • The first way is by making use of the function keyword.

So as an example, consider this piece of code :

function greet(name) { 
  return `Hey ${name}`;
}

This comes under normal functions that we declare when we write code. Another syntax that we often see getting used in the code is Function Expression Syntax

So let us transform the above function declaration into a function expression :

const greet = function(name) { 
  return `Hey ${name}`; 
}
  • The second way is using the arrow function syntax :

So let us transform the above code based on function expression to a code that uses the arrow function syntax

const greet = name => {
  return `Hey ${name}`;
}

Now if you see any of the above syntaxes can be used for defining functions, what you choose depends on you but knowing the differences between these syntaxes will make it easier to decide regarding the choice of syntax in different cases.

 this keyword

this keyword as we know is a property of an execution context. The main use of it is observed in functions and constructors. Here is a video where you can learn about the rules of the this keyword :

https://youtu.be/O5aShSPaMbE

  • Normal functions

this inside a normal function is dynamic. By dynamic, it means that the value of this depends on how we invoke the function. Let us see the ways we can invoke a normal function.
So during a normal invocation, the value of this equals to the global object. There is a small exception to this : If the function runs in strict mode, then the this keyword equals undefined. So let us see an example :

function someFunction() { 
   console.log(this);
}
someFunction(); 

The above examples logs the window object to the console.

Next, if we have a method that is sitting within an object, then the this keyword when referenced in the scope of method will point to the object that owns that particular methods which also represents the context in which that method is defined in.

So let us see an example for this as well :

const someObject =  { 
   greet() { 
        console.log(this);
        console.log('hello');
   }
};
someObject.greet(); 

So the above code calls the greet method that is sitting inside the someObject object.

Next we can also make use of the call method to perform an indirect invocation, here the value of this equals to the first argument that the call method receives.

function someFunction() { 
   console.log(this);
}
const someContext = { a : 'some value' };
someFunction.call(someContext); 

For the above example code, the this keyword points to the someContext object.

Next, let us see what this equals to in a constructor function that is created using the normal function syntax :

function User() { 
   console.log(this);
}
new User(); 

If we invoke the constructor function using the new keyword, then this equals to the newly created instance.

  • Arrow Functions

Arrow functions do not have their own this, instead they look up the scope chain to find a this that they can use (or until the lookup hits the global scope) much in the same way as a variable resolves its value. So if you reference a variable in a nested scope, then the lookup will go up the scope chain until it resolves its declaration. This in essence means that arrow function does not define its own execution context. This also means that no matter how or where the arrow functions get executed, the this value inside an arrow function always equals the this value from the outer function. IOW, arrow functions resolve the this in a lexical manner.

Let us take an example :

const someObject = { 
   someMethod(elements) { 
     console.log(this); 
     elements.forEach(element => { 
        console.log(element);
        console.log(this);
     });
   }
};
someObject.someMethod([1,2,3,4,5]);

this value inside the callback of forEach equals to this of the outer function someMethod

Constructors

  • Normal Functions We now know that normal functions can be used for creating new objects. So for example, if we want to create a new user, then we can create a constructor function with the name User and that will give us the ability to create new instances of a car when used with the new keyword. So let us see the code for this :
function User(name, age, profession) {  
  this.name = name; 
  this.age = age; 
  this.profession = profession;
}
const newUser = new User('alex', 21, 'developer');
console.log(newUser instanceof User); 

So if you see above, User is a normal function. When invoked with the new keyword, new User('alex', 21, 'developer') – new instances of User gets created.

  • Arrow Functions

Arrow functions cannot be used as constructor. So if you try to invoke an arrow function using the new keyword, JavaScript will yell at you with an error. So let us see an example for this as well :

const User = () => { 
   this.name = name; 
   this.age = age;
   this.profession = profession; 
}
const newUser = new User('alex',21, 'developer'); 

So for above code, invoking new User('alex', 21, 'developer') will throw an error, specifically this error :

TypeError: User is not a constructor

– Implicit Return

  • Normal Function

See the following code :

function someFunction() { 
  return 'some value';
} 
const value = someFunction(); 
console.log(value);

In the above code, we are just invoking the normal function someFunction and at the point of invocation, we receive a value which we store in value variable that we defined above. Now if we omit the return statement in the above code, or if there is no expression after the return statement, the normal function will do an implicit return here with the value of undefined. So let me demonstrate this with the help of an example :

function someFunction() { 
  'some value';
}
function someFunction2() { 
 return;
}
console.log(someFunction());
console.log(someFunction2()); 

In above code, the first console.log will give us undefined because it misses the return keyword, it actually returns nothing. Coming to the second console.log, it does return but there is no value as such, hence this is also undefined

  • Arrow Function

In case of an arrow function, you can perform implicit return but the condition for same is that your arrow function should contain only one expression. If so is the case, you can then omit the function’s curly braces, and simply do an implicit return for the expression. So let us see an example for this :

const multiplyBy2 = num => num * 2; 
console.log(multiplyBy2(3)); 

The multiplyBy2 arrow function if you see comprises of just one expression num => num * 2. So here the expression is implicitly returned by the arrow function
without the use of return keyword.

Methods

  • Normal Function

Normal functions as we know is the usual way for defining methods on classes.

Let us see an example :

class User {
   constructor(name, age, profession) {
       this.name = name; 
       this.age = age; 
       this.profession = profession; 
   }
   logUserDetails() { 
      console.log(this.name);
      console.log(this.age);
      console.log(this.profession); 
   } 
 } 
const user = new User('alex', 21, 'developer'); 
user.logUserDetails();  

So the above code does works. But let us assume that we need to supply the logUserDetails method as a callback, say for example to a setTimeout or some other event listener. Now in such cases, we may get a wrong context while trying to access the this value.
So consider this code :

setTimeout(user.logUserDetails, 1000);

So after 1 second, the above code will call the logUserDetails method on the user object. Now for the above code this points to the window object.

Let us manually fix the context so by correctly binding this value to point to the user object. So for this , we can make use of the bind method.

setTimeout(user.logUserDetails.bind(user), 1000);

In the above code, user.logUserDetails.bind(user) binds the this value to the user instance. So this ensures that we don’t loose the context and that the this keyword is correctly bound to the instance.

There is another workaround for this as well which is using arrow functions.

  • Arrow Function

Now with the introduction of class fields, we can use the arrow functions as methods inside classes.

Contrary to the normal functions, the method that we define using arrow functions binds this lexically to the instance of the class.

So let us see an example for same :

class User {
   constructor(name, age, profession) {
       this.name = name; 
       this.age = age; 
       this.profession = profession; 
   }
   logUserDetails = () => { 
      console.log(this.name);
      console.log(this.age);
      console.log(this.profession); 
   } 
 } 
const user = new User('alex', 21, 'developer'); 
user.logUserDetails();  

Now for the above code, if we use user.logUserDetails as a callback without even performing a bind, it will give us the correct values. The value of this inside our logUserDetails will be the class instance itself.
So if you try the below code, you will get alex21 and developer to the console as output.

setTimeout(user.logUserDetails, 1000);

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.