Suparth Narayan Ghimire

[email protected]
977-9848952466 🇳🇵
Kathmandu, Nepal


Github | Linkedin


Skills and Abilities

  • Excellent Proficiency in NodeJS and Express to create server side applications using REST APIs
  • Proficiency in TypeScript
  • Caching using Redis
  • Experience with Domain Management with Cloudflare
  • Great knowledge of Client Side Libraries and Frameworks - TailWindCSS, Mantine UI, Bootstrap, React, Next.js,
  • Experiece in working with version control - Git/GitHub
  • Worked on Multiple Projects using databases such as MySQL, ProstGreSQL, MongoDB, Firebase
  • Experience in Web Sockets using SocketIO
  • Knowledge of Devops: Docker, NGINX, Google Cloud
  • Good Understanding of C++

Work Experience

  • Sr. Full Stack Developer
    March 2023 - Current
    Swivt Techologies

  • NDA Issues.

  • Project Lead - The Wadi Tribe Mobile Application
    July 2022 - November 2022
    Freelance

    • Managing Team of 4 along with an International Client to create a Full Stack Application with Augmented Reality
    • Implemented fully featured REST API in Microservice Architecture with CRUD, Authentication and Authorization in Node JS using TypeScript and MySQL with Prisma ORM
    • Created Robust Admin Panel to fulfill neads of current and future projects in Next JS using TypeScript with TailwindCSS and MantineUI
  • Design System in Next.js
    March 2022 - July 2022
    Aspark Systems

    • Created Design System for a Educational Platform using custom CSS designs and React Bootstrap
    • Integrated Existing REST API to design components
  • Front End Application in Next JS
    December 2021 - February 2022
    Aspark Systems

    • Integrated Existing REST API with frontend design for company's long term client
    • Created Multiple Resuable Components in the Application along with using preexisting templates.

Projects and Community

  • Chess
    Game of Chess in Browser (On Going)

    • Local Multiplayer
    • Board Editing and Analysis
    • Github
    • Demo
  • Talk
    End to End Encrypted Chat Application

    • Chat Application that uses AES encryption and Diffie Hellman Key Exchange to let users Chat to each others securely
    • GitHub
    • Demo
  • ts-template
    CLI Tool

    • Initializes TypeScript Project using SWC compiler
    • Github | npm

Education

  • Tribhuvan University - BscCSIT 2019 - Current

You Don't Understand Statements (in JavaScript)

You think you do, but you dont.

What?

From the day we started to learn programming, few words are fed to us. Variables, constants, functions, classes, statements etc. All of them are very easy to understand, but something about statements always seem confusing. It is not something that needs to be understood completely to be able to write a program though! I mean we can all write a simple program to add two numbers in programming language of choice right? Even further, we can create a calculator application using if and switch statements along with arithmetic operators. Then what is all the fuss about? Why am I writing this blog? It might feel redundant at first, but believe me when I say you don't fully understand the meaning behind statements in low level computing (what compiler understands).

Why?

Why is this important? Why am I reading this blog? Why should I care about it when I can create a server to create REST APIs and an entire full stack application? I know how control statements work. What is your point?

Statements are fundamental building blocks that make or break a programming language. Knowing how something works does not mean you fully understand what it means. Many of us are not privy to the concept of how compilers work, and how the code we write gets compiled. The legend Linus Torvalds once said "If you think like a computer, writing C makes sense" and "When I read C, I know what the assembly language will look like"

Here is the video where he says this

You can intrepret this in anyway you like, but what I understand is writing code in a language means you need to understand what it is going on underneath. Knowing how to do something to make it work isn't enough.

Point?

Saying this, I know many of us already know the meaning of statements and how they work in respective programming language of choice. But I did a poll recently in an IT Community - ITSNP (its a great community. Join Here if you have not already)

The question was

  • Which of these is "objectively" the correct syntax of if statement in JavaScript?
    if (condition) statement;
    
    if (condition) {
      statement;
    }
    
    if(condition) {
        statement 1;
        statement 2;
        ...
    }
    

Answer it before moving further to see if you were correct.

Poll Result

This was the result of the Poll.

Poll Result

Before providing the answer to the question of the poll lets understand what statement means and how do they work.

Statements

We have all heard that variables/operators/functions make an expression and expressions make up statements.

Example:

a + b;

is an expression and

c = a + b;

is a statement

This shows that the common syntax for any sequence of characters to be a statement is

Generalization

variable = expression;

Okay. But we also have if statements, for statement, while statement? What are those? They don't follow this syntax. Are they not statements? They are. That is why this traditional definition of statement is not correct.

Correction

The correct definition of statement would be:

A command given to the computer to instruct it to perform some action.

The thing to note here is the phrase instruct it perform some action. Not task, but action. If you replace the word action by task then the definition:

A command given to the computer to instruct it to perform some task.

would define a program.

Action?

Action can be anything.

  • Perform arithmetic operation
  • Check for boolean logic
  • Jump to some other part of program etc.

These actions all are classified into different types in different programming languages.

In JavaScript some of them are as follows:

  • Expression Statement -> (all statements ending with semicolon ";")
  • Jump Statement -> (Function Calls)
  • Labeled Statement -> (Switch Case)
  • Selection Statement -> (if else statements)

However, compiler understands statements by generalizing them in 2 different types.

  • Simple Statement: Single Statement

Single Statements are usually written in a single line
Example:

let y = 3 + 10;

The next one is Compound Statement, which we will discuss after a while.

Statements in the Madness of CFG - Compiler Design

Note: to avoid confusion I am not writing the examples of CFG here in the preffered convention, but as simple single Uppercase characters

A compiler reads statement as a syntax. The syntax of a compiler is understood as a grammer. The grammer is known as Context Free Grammer or CFG.

A CFG for representing syntax for simple arithmetic statement can be written in this way

S -> id = E
E -> E + E | E - E | E * E | E / E | (E) | id

These are read as

  • S produces id = E
  • E produces E + E or E - E or E * E or E / E or (E) or id

This only is a simple representation. This does not represent everything

Here id is a terminal symbol (assume a variables for now) S and E are non terminal symbols. S means Syntax and E means Expression who are recursive in nature.

WTF?

I know this is confusing, but bear with me for a moment

Imagine this being a recursive function, where the production of terminal symbom (id) is the base case, and production of non terminal symbols (S and E) are recursive case.

Say a compiler has to parse this arithmetic statement

x = a + b - a / b;

Then a syntax tree is formed this way

Breakdown                    | Reason
-----------------------------------------------------------------------
S  -> id = E                 | (Production of S)
rm -> id = E - E             | (E produces E - E -> recursive breaking)
rm -> id = E - (E)           | (E produces (E) -> recursive breaking)
rm -> id = E - (E / E)       | (E produces E / E -> recursive breaking)
rm -> id = E - (E/id)        | (E produces id -> recursive breaking)
rm -> id = E - (id/id)       | (E produces id -> recursive breaking)
rm -> id = E + E - (id/id)   | (E produces E + E -> recursive breaking)
rm -> id = E + id - (id/id)  | (E produces id -> recursive breaking)
rm -> id = id + id - (id/id) | (E produces id -> recursive breaking)

rm means right most

the end of this recursive definition resulted in all production reaching a terminal symbol. This means the statement

x = a + b - a / b;

is correct.

This creates a syntax tree that looks like this

Syntax Tree

If you see closely, this approach is similar to solving a simplification problem using BODMAS rule. This is how compiler parses an arithmetic statement.

If you want to learn more about Context Free Grammers, here is a link to series of videos along with written material by Daniel Shiffman. Contect Free Grammer

I know this is confusing and it might seem like I am going off topic, but giving you context before jumping forwards was necessary.

Compound Statements

We discussed the syntax of a simple statement above right. Then what would be the syntax for a compound one?

First we need to change the way we define a simple statement, not as simple expression but a sentence of logic such as

  • It is raining
  • It is cold
    etc.

These are simple statements in logic, which are represented by

  • p: It is raining
  • q: It is cold

Compound statements then can be created by combining them using conjunctive words like and, or, if..then
Example:

Description Symbolic Statement
p and q p V q It is raining and it is cold
p or q p ^ q It is raining or it is cold

This shows that compound statements dont need to be in multiple lines. Compound statements mean combination of simple statements. Simple statements in multiple lines are called Collection of multiple statements. Collection of multiple simple statements are one of the production of compound statements.

Hence, c = a || b, d = a && b, etc. they all are compound statements as they combine two or more simple statements.

A question then, are a + b, a - b compound statements?

No. Why? These operators donot combine two statements, but they provide a single answer by doing an operation.

Answering the Mystery

Description Symbolic Statement
p implies q p => q If it is raining then it is cold

We see that if statements ar a compound statements as they comprise of multiple simple statements.

Hence, in JavaScript, if we had to create a production for if statement syntax, we would create it this way

Using proper naming convention for CFG here

<stmt> -> if(<expr>) <stmt>
<stmt> -> <compound_stmt>
<compound_stmt> -> { <stmt_list> }
<stmt_list> -> <stmt> <stmt_list> | epsilon

The answer

Compilers read code from a *.js file. They all are bunch of characters written together. We programmers write code in a way that the compiler understands. There are certain predefined structure to write a syntax for alot of statements. If being one of them.

The syntax above is how if statement is defined in JavaScript. What does that mean?

It means that whenever it encounters the word if, an opening parenthesis must follow it. There must be an expression following it. Expression here is a non terminal symbol, thus it's production is defined somewhere else. After expression ends, a closing parenthesis must follow.

The next thing we see is a non terminal symbol called stmt, not a opening curly brace. Stmt is a non terminal symbol which then yields a compound statement. This then yields another production that has a curly brace in front. However, stmt doesn't only yield a compound statement. Here are some that is produced by stmt

<stmt> -> id = <expr>;
<stmt> -> if (<expr>) <stmt>
<stmt> -> while (<expr>) <stmt>
<stmt> -> do (<expr>) <stmt>
<stmt> -> for (<stmt> <expr>; <expr>) <stmt>
<stmt> -> return <expr>;

And more. This is why these pieces of code are valid in JavaScript

if(true)
  if(true)
    if(true)
      let x = 7 + 10;

This is possible as this is parsed as

Breakdown                                                 | Reason
<stmt> -> if(<expr>) <stmt>                               | <stmt> is broken down to if(<expr>) <stmt>
    rm -> if(<expr>) if(<expr>) <stmt>                    | Same as Above
    rm -> if(<expr>) if(<expr>) if(<stmt>) <stmt>         | Same as Above
    rm -> if(<expr>) if(<expr>) if(<stmt>) id = <expr>;   | <stmt> is broken down to id = <expr>;

let i = 10;
if (true) while (i < 10) if (true) i++;
let i = 10;
if (true) while (i < 10) return true;
let i = 10;
if (true) {
  let z = i;
  i = i + 10;
}

Try to decode others by parsing them yourself.

Alternate Universe

Let's see if the production was abit different

If the syntax for if was this way

<stmt> -> if(<expr>) {<stmt_list>}
<stmt_list> -> <stmt> <stmt_list> | epsilon

Then only code that would be parsed would be

if (true) {
  return true;
}

This would be a valid JavaScript code
However,

if (true) return false;

This would return in syntax error.

I hope you got your answer at this point. The correct answer if the question of the poll is ... Drum Roll...

if (condition) statement;

Replacing condition with expression would be more correct as

if (6 + 7) console.log("This is valid");

is also a valid code in JavaScript, but you get the point.

Off!

This was a long one. I hope you now understand why statements are important and the complexity behind designing a statement in a programming language is very high.

Fun fact, compound statements are called block statements in JavaScript. This is where the infamouse block scope word comes from. What does that mean? Well, stay tuned as the next blog is all about scoping in JavaScript.

Leaving Statements

That is all I have in store for today. Stay tuned for upcomming blogs in the future.

Adios.

What is This? (in JavaScript)

We all developers have atleast once in our lifetime encountered the this keyword in many Programming Languages (self if you are from Python island). The implementation of this varies somewhat in all these languages, but it is not as confusing as it is in JavaScript.

Detour to C++

Before starting, lets see another famous programming language that utilizes the this keyword, C++.

The example here is true for most other languages as well

I think the implementation of this in C++ is as straight forward as it gets. It represents the current instance of the Class.
Let's See an Example

#include<iostream>
class Person{
public:
    std::string name;
    Person(std::string name){
        this->name = name;
    }
};
int main(){
    Person p = Person("Suparth");
    std::cout << p.name;
    return 0;
}

Here, we see that parameters in the constructor function have same name as the public variable names in the class. However, this makes it clear on which variable is the value being assigned to. Here this refers to the instance of the class.

this->name = name;

It means the value of variable name from parameter is being assigned to the variable name from the class instance.
Thus, while logging the value of name from object p, we get Suparth in terminal.

Doesn't Seem Complex does it? Well, buckle up, as we gear towards the island of JavaScript where everything is weird. Specially This!

Welcome to JavaScript

JavaScript's this has the same heart as other programming languages. It too refers to the current instance. But, the catch here is WHAT IN HELL DOES CURRENT INSTANCE MEAN?

Current Instance / Scope

JavaScript (by default) is a globally scoped language. It means you dont need to create any extra scope to execute code like in C++ or Java where you require a main method. Here you can execute code from first line itself. It is similar to Python in this regard. To achieve this, JavaScript has scopes/contexts where everything is executed.

Scopes in JavaScript:

  • Global Scope
  • Function Scope
  • Block Scope

We wont be going in what these scopes mean, as they are entirely different topic. Let's focus on this for now.

Some extra topics that you can learn that are based around Scopes in JavaScript

  • Hoisting
  • Closures

This in JavaScript

this refers to different things in JavaScript.

The basic gist of this in JavaScript is that this refers to the object of whatever scope is wrapping it. If the object of scope is not found, it refers to the parent's scope's object.

Confused? Let me elaborate.

We see that window is an object in JavaScript which is the object that represents the global scope. Block scope doesn't have any object that represents to it. Hence, if this is referred inside a simple block scope (within curly braces), it still refers to the window object as there is no other object for it to bind itself to.

By {}, I mean simple lexical scoping or using if statements, loops etc.

This Refering to Global Object

  • Global Scope
console.log(this);
  • Block Scope
if (true) {
  console.log(this);
}
  • Function Scope
function fn() {
  console.log(this);
}
fn();
  • Inside an Object
let obj = {
  thisKey: this,
};
console.log(obj.thisKey);

All these examples will print the window object in console.

Everything here has been explained by the paragraph above, except for last two examples of function and the object. The obvious question here is doesn't function have its own scope? And why does this not bind to Object?

Function: JavaScript functions are weird as well as magical. We can not only treat them as normal subroutines by simply calling them, but also as constructors by invoking them using the new keyword! Here, function fn has just been called like a normal subroutine. Thus, no constructor is created which does not create a function scope, but creates a local scope. And since no object corresponds to local scope, it looks at the parent scope of the function which is global scope. Since the corresponding object of global scope is window, this inside a function invoked by a simple function call refers to the global scope or window object.

Object: The answer to Object's example simple. Creating new object does not create any new scope, as obj is simply a variable (even though it uses curly braces). Thus, it refers to the global scope/window object as obj is created inside global scope.

The Prototype Carnival

Before moving forward, we must be familiar with prototypes and prototipal inheritance. I wont go much in detail, but here is a small brief.

Everything in JavaScript is an Object. If we see the prototype chain of anything in JavaScript, we see it is same as Object.Prototype. The Prototype of Object is null. Hence, in the top level of hierarchy, we see object being present.

This means function is an object too. If you run following code:

Function.prototype.__proto__ === Object.prototype;

We get true as the result.


This Refering to Certain Object

  • Functions as Constructors
function ConstructorFunction() {
  console.log(this);
}
const newInvoker = new ConstructorFunction();

What is new Here?

We see that the first distinction from normal function call is we invoke the ConstructorFunction function using new Keyword. This now creates a function scope within the global scope. When a function scope is created, the corresponding object is Function itself (function is an Object in JavaScript - discussed above). Hence, the this keyword will now refrence the function itself.

A more sophisticated example

function Game(initialScore) {
  this.score = initialScore;
  this.increaseScore = () => {
    this.score++;
  };
  this.decreaseScore = () => {
    this.score++;
  };
}

const newGame = new Game(0);
console.log(newGame.score);
newGame.increaseScore();
console.log(newGame.score);

The Output is:

0
1
  • Arrow Functions
const arrFunction = () => {
  console.log(this);
};
const arrFnNewInvoke = new arrFunction();

This will result in an error that says arrFunction is not a constructor.

Can you say why?

Arrow functions are not meant to be declared as constructors. Thus, they cannot be invoked using new keyword. Which means this keyword inside arrow functions will always point to the wrapper around the arrow function. In this case, it is the global scope/window object.


  • Function as Method inside an Object
let obj = {
    name:"Suparth"
    getName:function(){
        console.log(this)
    }
}
obj.getName();

Remember while discussing the global scope of this keyword, we said that in normal function call, this points to global object as the wrapper of the function itself is the global context? Well here the wrapper is the object obj. What do you think will this point to in this case?

You might think that as getName function is wrapped by an object obj, this should point to global/window because Object doesnot create any scoping, which results in this pointing to window itself.

The answer however is far more complex than that. Let's elaborate how objects are created in JavaScript.

let obj = new Object();
obj.name = "Suparth";
obj.getName = function () {
  console.log(this);
};
obj.getName();

Current block of code, and the one before this results in same behavior. The only difference is how we define objects, lattar one being a longer way to do so.

Do you see what we did here though? Do you remember we invoking a function using new keyword? Yes!!! This is same as invoking a function as a constructor. This is possible because Function is an Object in JavaScript.

Then what will this inside a constructor function point to? Yup. The constructor function itself! Hence the output here of obj.getName() will print the object obj itself.

  • Arrow Function as Object Method
let obj = {
    name:"Suparth"
    getName:()=>{
        console.log(this);
    }
}

What will this point to in this case?

If you say window object, you are absolutely correct. As arrow functions cannot act as constructor function, it wont bind to the object obj, but to the global scope/window object.

Classes - New Kids on the Block

Es6 was an interesting transition from Es5 in JavaScript island. Many new cool kids were added in the island who brought much needded changes that made the language much more redable and accessible. We all know the introduction of Promises and async/await, where async/await were the hot cakes. But well, classes were added too! So? How does this work in Classes? Well, how it always has! Let me explain.

You see classes in JavaScript is same thing as creating functions and invoking them as constructors using the new keyword. It just is a syntatic sugar similar to async/await. Thus, whatever we discussed before that includes Function, the concept here holds true.

class Person {
  constructor(p_name) {
    this.name = p_name;
  }
  getName() {
    console.log(this);
  }
}
const P = new Person("Suparth");

Well, you see the similarity? Calling function as a constructor is same as creating a class! It just is an declarative way to do so. This made JavaScript more closer to other Object Oriented Languages and made inheritance similar to other langauges as prototypes seemed weird before.

class Game {
  constructor(initialScore) {
    this.score = initialScore;
  }
  increaseScore() {
    this.score++;
  }
  decreaseScore() {
    this.score++;
  }
}
const newGame = new Game(0);
console.log(newGame.score);
newGame.increaseScore();
console.log(newGame.score);

Remember this Example from above? Well this is how we would do it using ES6 way. This proves that classes are nothing but a syntatic sugar to create more redable constructor functions.

Not Convinced? Well, run this code:

class DemoClass {}
console.log(typeof DemoClass);

The Output will be

"function"

Thus, nothing changes while using this keyword inside classes in JavaScript.

Leaving JavaScript

That is all I have in store for today. this isn't over by the way! this has alot more to be explored upon. Did you know, you could modify behavior of this in JavaScript? Well, stay tuned for more blogs, as more of this is yet to be discussed.

Adios

Functional Programming in JavaScript and Following the DRY Principle

Introduction

We all have used JavaScript and probably have felt in love with it. If not, I don't blame you! Its not that easy of a language to work with. However, JavaScript does provide some amazing features that you can leverage to write very clean code to follow the DRY principle. One of those features is Functional Programming.


Example

We all have used multiple built in methods in JavaScript, and have felt in love with it. Lets one of them here:

1. Classic Foreach

const array = [1, 2, 3, 4, 5];

array.forEach((item) => {
  console.log(item);
});

Here each item of array is iterated over once and certain operation is performed. But if we take a closer look, the actual implementation of forEach is hidden from us. We have no idea how it is written in the spec of the language. We only know how to use it (This is called Abstraction in programming). And yet, we can pass almost any valid JavaScript statement and it does the job! How? This is the beauty of Functional Programming. We as programmers can provide a function itself that can perform certain task for us.

The alternative to this forEach method would be a traditional for loop as

const array = [1, 2, 3, 4, 5];
for (let i = 0; i < array.length; i++) {
  console.log(array[i]);
}

Note: I agree that traditional for loop is way faster than its forEach counterpart, but lets give that a pass it for now.

Now, what is the problem with this? Why not use a traditional for loop and why to use the forEach method?
Well the answer is only for better readability. However, if the amount of data to iterate over is not large, then using forEach over traditional for loop doesnot provide much performance boost.


How is it implemented?

Okay. Enough of the performance jibber jabber. Lets see how is it implemented.

Now, we all know that functions can be assigned to variables in javascript.

const fnName = function (...args) {
  return;
};

This is a valid statement. If you dont come from a background of statically typed languages, this might seem trivial, but believe me its next to magic that we can do this. Golang supports this btw even though it is a statically typed language, but most others donot. C/C++, JAVA, C# donot support functions as variables. Infact, C# uses delegates to do what JavaScript does.


Your Point?

The magical thing this lets us do is pass functions as arguments to other functions!
Huh? What?
You know like any variable in JavaScript can be passed as argument to other functions like this?

function sum(a, b) {
  return a + b;
}

function init() {
  const aNum = 12;
  const bNum = 40;
  const sum = calcSum(aNum, bNum);
}
init();

Likewise, we can pass functions itself! Woah! What? Lets see an example:

function callOtherFunction(functionName) {
  functionName();
}

function init() {
  const functionVariable = function () {
    console.log("I am being Called");
  };
  callOtherFunction(functionVariable);
}
init();

The output you get is

I am being Called

You see the magic? We are calling the function by passing it as a parameter to other function! It is infact breaching its lexical scope!
Okay.... So What?


The Implementation

Lets say we want to iterate over an array of data and log it to the console. Lets write a function that logs any data to console.

function LogValue(data) {
  console.log(data);
}

Now, We require an array of data. Lets create one above the LogValue function

const data = [1, 2, 3, 4, 5];
const LogValue = function (data) {
  console.log(data);
};

Now, we want to iterate over the data array and run the LogValue function over every item in the array thus, we can create a function that takes array and any action we wish to perform as arguments and simply iterate over the array and run the action function

const data = [1, 2, 3, 4, 5];
const LogValue = function (data) {
  console.log(data);
};
function MyForEach(array, action) {
  for (let i = 0; i < array.length; i++) {
    action(data[i]);
  }
}

Finally, lets call MyForEach function by providing data and LogValue as its arguments

const data = [1, 2, 3, 4, 5];
const LogValue = function (data) {
  console.log(data);
};
function MyForEach(array, action) {
  for (let i = 0; i < array.length; i++) {
    action(data[i]);
  }
}
MyForEach(data, LogValue);

This will give same output as this block of code

const data = [1, 2, 3, 4, 5];
data.forEach(LogValue);

If you wish to use arrow function instead, we can do this

const data = [1, 2, 3, 4, 5];
function MyForEach(array, action) {
  for (let i = 0; i < array.length; i++) {
    action(data[i]);
  }
}
MyForEach(data, (item) => {
  console.log(item);
});

This will provide same output as

const data = [1, 2, 3, 4, 5];
data.forEach((item) => {
  console.log(item);
});

Now for the final show, we see that our implementation doesnot looks as good as the in built one right? I mean while using arrow function we cant even say what is going on in our code. In the native implementation we see that the code is far more readable. Well fear not! We can easily add our implementation to the existing Array method's prototype to use it in just the same way as the traditional forEach method

const data = [1, 2, 3, 4, 5];
/*
 * Instead of this,
 * function MyForEach(array, action){
 *     for(let i=0; i<array.length; i++){
 *         action(data[i])
 *     }
 * }
 * MyForEach(data, item=>{
 *     console.log(item)
 * })
 */
Array.prototype.MyForEach = function (action) {
  for (let i = 0; i < this.length; i++) {
    action(this[i]);
  }
};
data.MyForEach((item) => {
  console.log(item);
});

You can use this method now to do everything that forEach does in JavaScript!
Isnt it remarkable that you can do this? This can lead to you not repeating yourself, essentially making you follow the DRY principle. Write a generic function once and use it wherever on your project!


Conclusion

JavaScript is filled with fun things like this that you can explore and imporove your approach in writing code. Making a habit of utilizing the language with many features that it provides will help you become a better developer.
I will leave you here with the implementation of the most useful map method used in JS array that returns another array by performing an operation. I hope you liked this blog, and I hope this helped you get into more complex and advanced topic in JavaScript.

The Map Method

Array.prototype.MyMap = function (action) {
  const newArray = [];
  for (let i = 0; i < this.length; i++) {
    newArray.push(action(this[i]));
  }
  return newArray;
};
function init() {
  const data = [4, 5, 6, 7, 8, 9];
  //JS Built Implementation of Map
  const jsMapAns = data.map((item) => {
    return item + 5 * 3;
  });
  //My Implementation of Map
  const myMapAns = data.MyMap((item) => {
    return item + 5 * 3;
  });

  console.log(jsMapAns, myMapAns, jsMapAns.toString() === myMapAns.toString());
}
init();

Use Clever Math to Make Responsive Carousel

BEFORE WE BEGIN, THIS IS NOT ANOTHER NPM PACKAGE

I have used a lot of carousel components in the past, and they work good, but none of them work as expected. They often require static values when you want to make them responsive. I have decided to make my own carousel component that is responsive (on any screen size) without providing any static screen size values.

Problem

The problem that we have on hand by looking at some popular carousel components.

  1. React Slick Good Features, but requires custom hard coded values for responsive design.
  2. Mantine Carousel Good Features, but requires custom hard coded values for responsive design.
  3. React Responsive Carousel Good Features, but requires custom hard coded values for responsive design.
  4. React Multi Carousel Good Features, but requires custom hard coded values for responsive design.
  5. Swiper Good Features, but requires custom hard coded values for responsive design. Also, it says ReactComponent version will be deprecated in favor of web-componenjsx, which are not supported well in React yet.

See a pattern here? All of these need hard coded values to make them responsive.

All of these component packages, though they provide great deal of customization and features, require hard coded values to make them responsive.

This is something we often see in these componenjsx

const responsive = {
  desktop: {
    breakpoint: { max: 3000, min: 1024 },
    items: 5,
    slidesToSlide: 5, // optional, default to 1.
  },
  tablet: {
    breakpoint: { max: 1024, min: 464 },
    items: 3,
    slidesToSlide: 3, // optional, default to 1.
  },
  mobile: {
    breakpoint: { max: 464, min: 0 },
    items: 1,
    slidesToSlide: 1, // optional, default to 1.
  },
};

What if I don't want to specify these values and want them to be dynamic? The major drawback of this is that the size of carousel in different screens dictates the size of inner carousel child components. This really hard to maintain.

Objective

I have one job, To make a carousel with NO HARD CODED VALUES

Demo and Tech Stack

View Demo

I will be using the things that are popular at the time being to create the carousel and which probably will be used in many of your projects.

Setup

  1. Get the code

    git clone
    cd carousel
    
  2. Install Dependencies

    yarn
    

    or

    npm install
    
  3. Start the dev server

    yarn dev
    

    or

    npm run dev
    
  4. Open http://localhost:5173 to view it in the browser.

Explanation

We will be using the useMeasure hook to get the width of our carousel. We will also be using the useTransform hook from react-use-measure that provides bounds for the carousel and finally, we will use framer-motion for animation.

Lets jump into Carousel Components to see the props it takes

type PropsWithoutAutoplay = {
  autoPlay?: false,
  hideControls?: boolean,
  batchScroll?: boolean,
};
type PropsWithAutoplay = {
  autoPlay: true,
  interval: number,
};
type CommonProps = {
  spacing?: number,
  hideControls?: boolean,
  batchScroll?: boolean,
  scaleOnHover?: boolean,
  children: React.ReactNode,
  pagination?: boolean,
};
type Props = (PropsWithoutAutoplay | PropsWithAutoplay) & CommonProps;

Most of these are self explanatory, but I will explain the ones that are not.

  • autoPlay - If you want the carousel to auto play, set this to true. If you don't want it to auto play, set it to false or don't pass it at all.

  • interval - If you want to set the interval for auto play, pass this prop. The default value is 3000ms.

  • spacing - If you want to set the spacing between the carousel items, pass this prop. The default value is 0.

  • hideControls - If you want to hide the controls, pass this prop. The default value is false.

  • batchScroll - If you want to scroll multiple items at once, pass this prop. The default value is false.

  • scaleOnHover - If you want to scale the carousel items on hover, pass this prop. The default value is false.

  • pagination - If you want to show the pagination, pass this prop. The default value is false.

  • children - The children of the carousel. This is where you will pass the carousel items.

Lets look at the state variables for the component

const [activeCardIdx, setActiveCardIdx] = useState(0);
const [scrollAmount, setScrollAmount] = useState(0);
const [containerRef, containerBounds] = useMeasure();
const [childRef, childBounds] = useMeasure();
  • activeCardIdx - This is the index of the active carousel item. This is used to show the active carousel item.

  • scrollAmount - This is the amount of scroll that we want to do. This is used to scroll the carousel.

  • containerRef and containerBounds - This is the ref of the container of the carousel. This is used to get the width of the container.

  • childRef and childBounds - This is the ref of the carousel item. This is used to get the width of the carousel item.

We need to convert the items in children prop into array so that we can use map on it later on to render the carousel items.

const ITEMS = useMemo<React.ReactNode[]>(() => {
  if (Array.isArray(props.children))
    return props.children.map((child) => child);
  else return [props.children];
}, [props.children]);

The useMemo hook is used here to memoize the array of carousel items. This is done so that we don't have to convert the children prop into array on every render. If we don't use useMemo, the carousel will be re-rendered on every scroll.

The next step is to setup some default values for the carousel.

const parentWidth = containerBounds.width;
const childWidth = childBounds.width;

const spacing = useMemo(() => props.spacing || 10, []);

const SCALE_FACTOR = useMemo(() => 1.1, []);
const ITEMS_IN_VIEW = useMemo(
  () => Math.floor((parentWidth - spacing * 4) / (childWidth + spacing * 4)),
  [parentWidth, childWidth]
);

Everything here is self explanatory. The only thing that is not is the ITEMS_IN_VIEW variable. This is the number of carousel items that can be shown in the carousel at a time. This is calculated by dividing the width of the carousel by the width of the carousel item.

The use of useMemo here is to memoize the value of ITEMS_IN_VIEW. This is done so that we don't have to calculate the value of ITEMS_IN_VIEW on every render, rather only when the value of parentWidth or childWidth changes.

Say the width of the parent container is 1000px and each carousel item 's width is 200px. Now say the spacing is 10px. So the width of the carousel item will be

Padding Space = 2 * 10px = 20px
Gap Space = 2 * 10px = 20px
Total Space = 40px
Width of Carousel Item = 200px + 40px = 240px

Since we are using same value for Padding and Gap between the carousel items, we are multiplying the spacing by 4.

The total items, of width 240px, that can be viewed within the container, of width 1000px, is Math.floor(1000px/240px) = 4. Hence container can only fit 4 items at a time.

We have initialized all the state variables and calculated the default values except for the scrollAmount. This is because we need to calculate the scrollAmount only when the carousel is scrolled. So we will do that in the useEffect hook

useEffect(() => {
  const current = Math.floor(activeCardIdx / ITEMS_IN_VIEW);
  const prev = Math.floor((activeCardIdx - 1) / ITEMS_IN_VIEW);
  const next = Math.floor((activeCardIdx + 1) / ITEMS_IN_VIEW);
  let amt = 0;
  if (props.batchScroll) {
    if (current === prev)
      amt = -(childWidth + spacing * 4) * prev * ITEMS_IN_VIEW;
    else if (current === next)
      amt = -(childWidth + spacing * 4) * current * ITEMS_IN_VIEW;
    else
      amt =
        activeCardIdx >= ITEMS_IN_VIEW % activeCardIdx
          ? -(childWidth + spacing * 4) * activeCardIdx
          : 0;
  } else {
    amt =
      activeCardIdx >= ITEMS_IN_VIEW % activeCardIdx
        ? -(childWidth + spacing * 4) * activeCardIdx
        : 0;
  }
  setScrollAmount(amt);
}, [activeCardIdx]);

The useEffect hook is used here to calculate the scrollAmount whenever the activeCardIdx changes. The useEffect hook takes a callback function as the first argument and an array of dependencies as the second argument. The callback function is called whenever the value of any of the dependencies changes.

In our case, the callback function here will be called whenever the value of activeCardIdx changes. The activeCardIdx changes when the user clicks on the next or previous button or when the carousel auto plays.

To change the activeCardIdx, we will use the setActiveCardIdx function. This function takes the index of the carousel item that we want to show as the argument.

The final thing before creating our UI is to create a useEffect hook which runs the callback function on component mount; which means empty dependency array. This hook is to automatically play the carousel, this we need to set the interval for auto play.

useEffect(() => {
  if (!props.autoPlay || !props.interval) return;
  const selfIncTimerInterval = setInterval(() => {
    setActiveCardIdx((prevCardIdx) => {
      return prevCardIdx + 1 >= ITEMS.length ? 0 : prevCardIdx + 1;
    });
  }, props.interval);
  return () => {
    clearInterval(selfIncTimerInterval);
  };
}, []);

The callback function here will be called on component mount. The callback function here is to set the interval for auto play. The interval is set to the value of the interval prop. The interval prop is the time in milliseconds after which the carousel will auto play.

We need to return a function from the callback function. This function will be called when the component unmounts. This function is used to clear the interval. This is done so that the interval is cleared when the component unmounts. If we don't clear the interval, the callback function will be called even after the component unmounts. This will cause weird behavior in the app.

Now that we have all the state variables and the useEffect hooks, we can create our UI.

return (
  <div className="w-full grid items-center " ref={containerRef}>
    <div className="w-full grid items-center">
      <div
        id="carousel-wrapper"
        className={`flex overflow-x-hidden py-5`}
        style={{
          gap: `${spacing * 4}px`,
          paddingLeft: `${spacing * 4}px`,
          paddingRight: `${spacing * 4}px`,
        }}
      >
        {ITEMS.map((item, idx) => (
          <AnimatePresence key={`carousel-item-${idx}`}>
            <motion.div
              ref={childRef}
              className="flex-1"
              initial={{
                scale: 1,
              }}
              whileHover={{
                scale:
                  activeCardIdx === idx
                    ? SCALE_FACTOR
                    : props.scaleOnHover
                    ? SCALE_FACTOR
                    : 1,
              }}
              animate={{
                scale: idx === activeCardIdx ? 1 * SCALE_FACTOR : 1,
                x: scrollAmount,
              }}
            >
              {item}
            </motion.div>
          </AnimatePresence>
        ))}
      </div>

      <div className="w-full grid place-items-center">
        {props.pagination && (
          <div className="mt-5 h-full flex gap-2">
            {ITEMS.map((_, idx) => (
              <button
                onClick={() => {
                  setActiveCardIdx(idx);
                }}
                key={`pagination-carousel-${idx}`}
                className={`w-[10px] h-[10px] ${
                  idx === activeCardIdx ? "bg-neutral-900" : "bg-neutral-300"
                } rounded-full`}
              />
            ))}
          </div>
        )}
      </div>
      <>
        {!props.hideControls && (
          <div className="flex w-full justify-center spacing-2 w-1/5 mt-5">
            <button
              onClick={() => {
                setActiveCardIdx((prevCardIdx) => {
                  return prevCardIdx - 1 < 0
                    ? ITEMS.length - 1
                    : prevCardIdx - 1;
                });
              }}
              className="p-2 w-1/5 bg-black text-white hover:bg-neutral-600 transition"
            >
              {"<"}
            </button>
            <button
              onClick={() => {
                setActiveCardIdx((prevCardIdx) => {
                  return prevCardIdx + 1 >= ITEMS.length ? 0 : prevCardIdx + 1;
                });
              }}
              className="p-2 w-1/5 bg-black text-white hover:bg-neutral-600 transition"
            >
              {">"}
            </button>
          </div>
        )}
      </>
    </div>
  </div>
);

Lets look at the code below the actual carousel and finish it before moving on to the carousel component.

We see that if the pagination prop is true, we render a div with the pagination buttons. The pagination buttons are rendered using the ITEMS array. The ITEMS array is the array of items that we pass to the carousel component. The ITEMS array is mapped to render a button for each item. The onClick handler of the button is set to a function which sets the activeCardIdx to the index of the item that the button is for.

We can also see that if the hideControls prop is false, we render a div with the next and previous buttons. The onClick handler of the buttons is set to a function which sets the activeCardIdx to the index of the previous or next item.

Now for the actual carousel component

We see that the carousel component has the outermost div with the width of full parent's width and the ref is th containerRef. This one defines the width of the carousel. The ref is set to the containerRef so that we can get the width of the carousel.

The next div is the one which contains extra items for carousel such as pagination and controls.

The next div contains the carousel items, and its width is set to the width of the carousel. The gap, paddingLeft and paddingRight are set to the value of the spacing * 4. This is done so that the carousel items are not cut off when the carousel is scrolled.

Why 4?

We are adding spacing on 4 sides of each component. PaddingLeft, paddingRight and gap. So we need to multiply the spacing by 4.

Rendering the Carousel Items

Each element in ITEMS array is rendered by wrapping them inside two components provided by framer-motion. The first component is the AnimatePresence component. This component is used to animate the elements when they are added or removed from the DOM. The second component is the motion.div component. This component is used to animate the elements when they are added or removed from the DOM.

AnimatePresence can animate the elements not only when the children components are mounted, but when they are unmounted. This means exit animations can be played when the children components are unmounted.

The motion.div component is an addition to the html div element. This component can be used to animate the div element. The motion.div component has the initial, whileHover, animate props. The initial prop is used to set the initial state of the element. The whileHover prop is used to set the state of the element when the element is hovered. The animate prop is used to set the state of the element when the element is mounted.

We need to set the key of the AnimatePresence component to carousel-item-${idx}. This is done so that the AnimatePresence component can animate the elements when they are added or removed from the DOM.

The motion.div component has the ref prop set to the childRef. This is done so that we can get the width of the carousel items.

The motion.div component has the initial prop set to an object with the scale property set to 1. This is done so that the carousel items are not scaled when they are mounted.

When user hovers, if the scaleOnHover is true, the items should be scaled by factor of SCALE_FACTOR. But, the active item already has a scale of SCALE_FACTOR. So, if the scaleOnHover is true, and if the hovering item is not the active item, the item should be scaled by factor of SCALE_FACTOR. If the scaleOnHover is false, the item should not be scaled.

Each div should be animated by the x and the scale property. The x property defines the translation of the element along the x-axis. The x property is set to the scrollAmount whose value is calculated using the activeCardIdx and the width of the carousel items above inside the useEffect hook.

The scale property is set to the idx === activeCardIdx ? 1 * SCALE_FACTOR : 1. This is done so that the active item is scaled by factor of SCALE_FACTOR.

We finally set the child of motion.div to be the actual item that we want to render.

Thats It! We got it

Now we can use the Carousel Component inside any component that we want to use it in. We can pass the items that we want to render in the carousel as the items prop. We can also pass the pagination prop to render the pagination buttons. We can also pass the hideControls prop to hide the next and previous buttons. The carousel is responsive by design and will work on any screen size, or on any size of the parent's div. The only thing you need to worry is the width of the child element. The child element should be visible within the parent div.

Conclusion

We can now use the carousel component with variations like this

import React from "react";
import Card from "./components/Card";
import Carousel from "./components/Carousel";
import { ITEMS } from "./utils/mockdata";

export default function App() {
  return (
    <div className="flex flex-col gap-10 p-10 overflow-y-hidden">
      <Wrapper>
        <h1 className="font-bold text-lg px-7">Individual Scroll</h1>
        <div className="w-full overflow-y-hidden">
          <Carousel>
            {ITEMS.map((item, idx) => (
              <Card item={item} key={`carousel-default-${idx}`} />
            ))}
          </Carousel>
        </div>
      </Wrapper>
      <Wrapper>
        <h1 className="font-bold text-lg px-7">Pagination</h1>
        <div className="w-full overflow-y-hidden">
          <Carousel pagination>
            {ITEMS.map((item, idx) => (
              <Card item={item} key={`carousel-default-${idx}`} />
            ))}
          </Carousel>
        </div>
      </Wrapper>
      <Wrapper>
        <h1 className="font-bold text-lg px-7">Scale on Hover</h1>
        <div className="w-full overflow-y-hidden">
          <Carousel scaleOnHover>
            {ITEMS.map((item, idx) => (
              <Card item={item} key={`carousel-default-${idx}`} />
            ))}
          </Carousel>
        </div>
      </Wrapper>
      <Wrapper>
        <h1 className="font-bold text-lg px-7">Custom Spacing</h1>
        <div className="w-full overflow-y-hidden">
          <Carousel spacing={20}>
            {ITEMS.map((item, idx) => (
              <Card item={item} key={`carousel-default-${idx}`} />
            ))}
          </Carousel>
        </div>
      </Wrapper>
      <Wrapper>
        <h1 className="font-bold text-lg px-7">Batch Scroll</h1>
        <div className="w-full overflow-y-hidden">
          <Carousel batchScroll>
            {ITEMS.map((item, idx) => (
              <Card item={item} key={`carousel-default-${idx}`} />
            ))}
          </Carousel>
        </div>
      </Wrapper>
      <Wrapper>
        <h1 className="font-bold text-lg px-7">Automatic Scroll</h1>
        <div className="w-full overflow-y-hidden">
          <Carousel pagination autoPlay interval={1000} hideControls>
            {ITEMS.map((item, idx) => (
              <Card item={item} key={`carousel-default-${idx}`} />
            ))}
          </Carousel>
        </div>
      </Wrapper>
      <Wrapper>
        <h1 className="font-bold text-lg px-7">Automatic Batch Scroll</h1>
        <div className="w-full overflow-y-hidden">
          <Carousel batchScroll autoPlay interval={500} hideControls>
            {ITEMS.map((item, idx) => (
              <Card item={item} key={`carousel-default-${idx}`} />
            ))}
          </Carousel>
        </div>
      </Wrapper>
    </div>
  );
}

function Wrapper({ children }: { children: React.ReactNode }) {
  return <div className="w-full bg-neutral-200 py-5 rounded">{children}</div>;
}

That all for this tutorial. I hope you enjoyed it. If you find any issues, add them in the github repository. This is not a react component that you can npm install though. You can copy the code and use it in your project. If you want to use it as a react component, you can fork the repository and make it into a react component. I will be happy to merge your pull request.

Alright! Bye now.