Befriending Javascript...
Before the internet, life was very different than today. Although few things remained the same then and now, eating (food), sleeping, etc. But, Before the internet, there was nothing such as digital, the only forms of communication were physical or vocal. Back then, you had to step out of the house to socialize.
The above diagram illustrated how life was before the internet applications, service providers took over.
Henceforth before the Internet people were more somatic than virtual. All this changed slowly but rapidly after the Internet revolution, and people started eating more. Tada! not eating food but eating content, consuming services, etc.
Internet & Web
Internet is the combination of both hardware and software intertwined. There is a vast infrastructure that goes behind the hardware of the Internet. The cabling and the external wiring are levied in a specific pattern emerging as the Internet source. There's a fab website that tells about how this all is carried.
The only entry points of Internet sources in India are Mumbai, Cochin, Chennai, Trivandrum, and Tuticorin.
Now coming to the Web is the only way to access information online. According to the books, the Web is a system of Internet servers that support specially formatted documents. The documents are formatted in a markup language called HTML, or Hypertext Markup Language, which supports several features, including links and multimedia. In addition, these documents are interlinked using hypertext links and are accessible via the Internet.
But! But! But!
Yes, I am not moving away from the context like Anand from KGF 😅😅😅
The creation of the Web started the relevance of the Internet and JavaScript approximately 30 years ago when the first ever web page was gone live. However, the Web is incomplete without JavaScript. Let's look into some examples of web pages with JavaScript disabled.
- Netflix doesn't load anything except the logo.
2. G-mail without JavaScript
Hence, from the above example World Wide Web, aka Web without JavaScript, is like a plant 🪴 in a dark room with no water💧, sunlight ☀️, or space to breathe and live. Similarly, the Web without JavaScript is a read-only page with no user interactions, data, or functionalities.
Javascript: The Rise
Human lives today are dependent on the interactivity JavaScript provides. The above section has described how the web looks without JavaScript.We are, to a reasonable degree, dependent on JavaScript to function.
Today, virtually every computing device, including iPhones, Android phones, macOS, Windows, Linux, smart TVs, etc., has JavaScript interpreters installed on them and in active use. Currently, there are 1.8 billion websites worldwide, and 95% of them use JavaScript. The following is an illustration of the facts.
As you can see from the above, How many ever languages come over the next years Javascript is like "Main Jhukega Nai"
Javascript: The Rule
Let's understand how to rule the web in this section using Javascript and move closer to the objective of this blog.
The world is growing rapidly through tech and slowly moving towards the Digital spectrum. In this race of automation, new tools, libraries, and frameworks are being released almost every fortnight. Through this rapid change, there has been a bit of ignorance towards the language, especially in the younger part of the community. Although, it's necessary to adapt to the latest libraries, and frameworks it's more necessary to understand the language first. Language is evergreen and is like the foundation pillars of a building. How much ever the structure, amenities, and interiors of the building keep changing, the foundations laid over will be constant.
The objective of this blog post is to understand JavaScript in a better way through the help of a small application. Presenting the WindBnb, an application developed in pure JavaScript and CSS/SCSS without using any frameworks/library to understand the hidden concepts that are abstracted while using a framework/library but learning them might make you better in the journey.
Design Analogy 🔖
The design is the core of any application that can form an inflection in the development process. A proper design symmetry eases the whole process of the project. As the design philosophy of the application was desktop-first, it required an approach with minimal costs in the style changes and additions. As most of the application is dynamic, the style management needed to be optimized so as not to take a toll on the performance.
It has all the features required for this approach, and the few left are taken care of by its pre-processor SASS. CSS concepts like grid, flex and responsive units are majorly a part of the design language. The layout is held using the grid system as that helps in the viewport scalability. The flexbox is the best choice for internal elements like cards, drawers, etc. Finally, responsive units like rem, vw, and vh add to the overall acoustics of the design.
De-ciphering the Markup
The application's markup is written to be easily tailored and accessed through Javascript. The BEM class notation is followed in the markup. There are three main parts of BEM.
- The block holds everything (elements) inside and acts as a scope.
- The element acts as a specific part of the component. It should be prefixed with the block name, and followed by two underscores. Eg:
head__eye
,header__nose
, etc. - Modifier which adds additional styles to a specific element(s). It should be prefixed with either the block or the element name, and two hyphens. Eg:
head__eye—left
,head__eye—right
, etc.
This sums up the acronym BEM. Let’s understand this better below. Following are the sections inside the markup.
Note: The whole markup of the application is inside a wrapper div
with the class container
.
- Header Section
Block
header
element with the classheader
Elements
div
with the classheader__logo
div
with the classheader__search
div
with the classsearch__city
div
with the classsearch__guests
div
with the classsearch__icon
Modifiers - None
2. Header Overlay Section
Block
div
with the classoverlay
Elements
div
with the classoverlay__close
div
with the classoverlay__search
div
with the classbtn__search
Modifiers
div
with the classoverlay__close—icon
div
with the classbtn__search—icon
3. Main Section (Here, Javascript will inject the HTML dynamically)
Block
div
with the classstay
Elements
div
with the classstay__img
div
with the classstay__details
div
with the classstay__title
Modifiers
None
Architecture
After the initial baby steps of designing the application, the next phase in the same section is architecting the application. The application's architecture helps to understand many crucial parts of the app. Although Javascript has no features to follow MVC/MVT, they can be implemented explicitly. WindBnb follows the MVC pattern where a central controller directs the whole application between the Model (data) and views (UI elements). It also follows the 7-in-1 architecture of the SASS with partials and main files.
Understanding the Modular Structure
Explaining some of the essential files
appController.js
Here is the application's entry point and the single control source for the whole application. The following are some of the important jobs of this file.
- Creating the instance to the Model class, passing the mock data as the argument, and storing the instance.
- Creating the instance to the App View class and passing the stored model instance.
- Implementing & Controlling the Search Functionality.
appModel.js
Here is the model layer of the application. The following are the jobs carried out by this file.
- Receiving the Mock Data and storing it in the internal data structure.
- Util methods related to the data alteration related to filtering.
appView.js
Here is the root view component of the application. The following are some of the essential jobs carried out by this file.
- Creating the instance of the individual view classes, and passing the model instance received from the controller.
- Selecting and Storing the references to the DOM elements.
- Adding the event listeners and performing individual user actions.
- Initializing & Processing the search functionality and rendering the search data.
- Injecting the dynamic HTML to the DOM as per the use case.
Frameworks behind the scene and comparison with JavaScript
Frameworks and Libraries come with plenty of features that can rapidly improve the speed of development. Although, using a framework or library can be like constructing a building by integrating many blocks, not necessarily knowing each block individually. Following are some of the discussion points of language vs. framework/library. The scope of discussion of this blog is only restricted to React.
- Deep dive into JSX
Let's take a small code snippet from the WindBnb. The objective of the following function is pretty straightforward, i.e., accepting two arguments and returning the markup as a string.
Now, let's create a React functional component for the same use case. The following component's objective is the same as the above Javascript function.
We can draw the following observations from the above.
- Both Javascript function and React functional component are very similar syntactically.
- The Javascript function accepts arguments individually, but React component takes arguments/props as an object that can be de-structured.
- In the React functional component, className is used instead of class in JSX because the class is a JavaScript keyword, and xlinkHref is used instead of xlink:href as SVG tags should be written in camelCase.
Let's tweak the Javascript function and rewrite the same functionality in the DOM way. The following is the DOM structure for the above markup.
- Stay Details Container Node (Root)
- Stay Category Container Node
- Super Host Text Node
- Stay Type Text Node
- Stay Rating Container Node
- Star SVG Node
- Stay Rating Text Node
The above structure can be visualized as the below tree diagram that represents the DOM tree
Let's create a Javascript function replicating the above DOM structure.
document.createElement()
is used to create a DOM node and takes one argument i.e., the tagName, and returns a new element. It also takes a second argument that is out of the scope of this blog post.Element.className
is used to assign the classes to the element.Element.textContent
is used to assign the text content to the element.Element.appendChild()
is used to append the child node to the parent element/node.
Let's understand the previously written React JSX and how it works under the hood. Computers don't understand anything else except the machine language that gives instructions in 0's and 1's, and browsers also understand only HTML, CSS, and Javascript but not JSX. Behind the scenes, Babel does the job and compiles the JSX to React.createElement()
calls, where each JSX element is just syntactic sugar for calling React.createElement()
. Let's look into an example to understand this better by developing the same use case. The following is also known as React without JSX.
Let's briefly talk about the arguments of React.createElement()
.
- The first argument is to specify the
tagName
. This argument is the same as the first and mandatory argument of thedocument.createElement()
. - A second argument is an
object
that contains props specific to this element. - Finally, the last argument is the children of this component, like the nested elements of this component.
Now, let's look into them side-by-side to understand the concept better.
Key Points of Comparison:
- From the above comparison, it can be drawn that the left Javascript code snippet is similar to a React Functional Component.
- In React, you won't be using
document.createElement()
. However, ReactReact.createElement()
is similar todocument.createElement()
but there are also differences. document.createElement()
returns a DOM element (for example a div or an h1). WhereasReact.createElement()
returns an object that represents the DOM element.
Let’s see how these returns values look like
document.createElement()
const h1 = document.createElement('h1');
console.log(h1);
The above code returns
React.createElement()
const h1 = React.createElement("h1", {}, "Hello World");
console.log(h1);
The above code returns
As the library's job is to simplify the tasks, React.createElement()
simplifies the task of creating the element, and configuring everything in a single line. Whereas document.createElement()
typically needs 2-3 lines, one for making the element, another for setting the props, and the next to append the part.
2. Classy Coding
ECMA Script 2015 (ES6) introduced a new way of writing Javascript code using the Classes, providing a better way to follow object-oriented patterns. Let’s understand the classes in this section. Classes, especially in Front end community have become like Bajaj Chetak these days which gets spotted so rarely these days as people moved to Hero, Suzuki, and TVs respectively.
Similarly, in the Tech space developers have moved on to the Functional programming pattern. In React, Classes were used extensively till 2018 when hooks got introduced. In 2022, Classes are not React's way of creating components anymore but knowing them adds to the core of being a web developer. Let's try to understand them below.
Re-creating the same class in React is a little easy as the libraries' job is to make things easy.
Following are the essential tasks of the component.
- The constructor receives the props and manages the state of the component.
- Events are handled in the following way
class App extends React.Component {
constructor(props) {
...
...
this.handleHeaderSearch = this.handleHeaderSearch.bind(this);
}
handleHeaderSearch() {
...
...
...
}
render() {
return (
...
<div class="header__search margin-sm" onClick={handleHeaderSearch}>
<h2 className="search__city">Where do you travel?</h2>
<h2 className="search__guests">Add guests</h2>
<svg className="search__icon">
<use xlinkHref="assets/sprites.svg#icon-search"> </use>
</svg>
</div>
...
);
}
}
Why is binding required? Confused, will understand after this part
Only a single render method is responsible for rendering the component. (Refer to above code)
Dependency injection is handled from outside the component in a below way
(index.js)
import App from './App';
const rootElement = document.getElementById("root");
ReactDOM.render(<App data={...} cities={[...]} />, rootElement);
Why do we bind This?
While working on React, you must have come across controlled components and event handlers. We need to bind these methods to the component instance using .bind()
in our custom component’s constructor like how we have done in the above example.
Let’s try to understand, Why is that required?
Let’s see what happens if we do not bind the event handler method with its component instance in the below example.
class SampleThis extends React.Component{
constructor( props ){
super( props );
}
handleClick(event){
console.log(this); // 'this' is undefined
}
render(){
return (
<button type="button" onClick={this.handleClick}>
Click Me
</button>
);
}
}
ReactDOM.render(
<SampleThis />,
document.getElementById("app")
);
Let’s try to understand this undefined behavior
This has nothing to do with React, and the answer to this behavior lies in How Javascript is. The “this” in Javascript refers to the current object from where it’s being called. Understanding this with a few more examples below
Default Binding
function display(){
console.log(this); // 'this' will point to the global object
}
display();
This is a native function call. The value of this
inside the display()
method, in this case, is the window — or the global — object in non-strict mode. In strict mode, this
value is undefined
.
Implicit Binding
Now, putting the same function inside an object makes it behave like this
var obj = {
name: 'Rahul',
display: function() {
console.log(this.name); // 'this' here will point to the 'obj'
}
};
obj.display(); // Rahul
As discussed before, this
differs in the way where it’s being called. In the first example, the display()
function was called directly, hence it referred to the global object. In the second example, the display()
function was put inside an object and was called using that object. Hence, now this
pointed to that object.
Again Again
Again the catch here is, Suppose we assign this function reference to another variable and invoke the function using this new function reference, we get a different value of this
inside display()
var name = "global again!!!";
var outerDisplay = obj.display;
outerDisplay(); // global again!!!
This is how the behaviour of this
changes from use case to use case. In this case, the value of this
inside display()
falls back to default binding*.* It points to the global object or undefined
if the function being invoked uses strict mode. This is especially applicable while passing such functions as callbacks to another custom function, a third-party library function, or a built-in JavaScript function like setTimeout
that takes callbacks as arguments.
Hell Yes!!! That’s the sole reason why we need to bind this
in the class components when passing the event handlers as the callbacks from outside. As we observed in the React Component example, this
value was undefined
as the context was lost after passing the handler as a callback.
Wait a sec, Shouldn’t this
point to the global object in that case?
Answer: No! Because
The bodies of class declarations and class expressions are executed in strict mode
, that is the constructor, static, and prototype methods. Getter and setter functions are executed in strict mode.
You can read the full article about the same here.
So, to prevent this, we need to bind this
value like this:
class SampleThis {
constructor(name){
this.name = name
this.display = this.display.bind(this);
}
display(){
console.log(this.name);
}
}
var foo = new Foo('Rahul');
foo.display(); // Rahul
var display = foo.display;
display(); // Rahul
3. Doodling the DOM
DOM stands for Document Object Model. HTML
is the language of web pages. It provides the web page structure with many specialized tags, including the way to link multiple pages together. The structure of a web page is represented as a tree structure document object
. The JavaScript programming language can change the structure of this document object to bring dynamic behavior to the web pages. The DOM
(Document Object Model) is the programming interface for the tree structure web page documents. The document tree is called the DOM Tree
.
Now let's see if there’s a paragraph and if we have to change the text of the paragraph(the <p>
tag), we will need the ability to find the <p>
tag from the document tree and then set a new text value to it. We have to do all these using the JavaScript DOM APIs.
const paragraph = document.querySelector("p");
paragraph.innerText = 'Some other text!';
The mechanism of finding a particular node in the document tree is called Querying the DOM
. Adding a new node, deleting a node, or updating a node in the document tree is called DOM Manipulation
. The result of a DOM manipulation reflects on the web user interface. This process is called rendering
.
A few ways of Querying the DOM are
[document.querySelector](<https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector>)(selector)
[document.querySelectorAll](<https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll>)(name)
[document.createElement](<https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement>)(name)
element.[innerHTML](<https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML>)
Now the equivalent of the document.querySelector()
the method in React is using refs
. To select an element, set the ref
prop on it to the return value of calling the useRef()
hook and access the dom element using the current
property on the ref
, e.g. ref.current
.
How does React handle DOM?
React is a library that has a few layers of abstraction from the original DOM API. It provides something known refs
for accessing the DOM in this abstract way. In the real DOM, every time even changing inner text on that wee tiny <p> tag means having to re-render the whole Document!
As revisited many times in this blog libraries, and frameworks bring a lot of add-on things to the table simplifying the process. But, understanding the underlying concepts makes it, even more, simpler and a better developer. So, React works with a Virtual DOM. It keeps a track of changes in its own Virtual DOM before ‘mounting’ to the old school DOM in the way it deems most efficient.
useRef
useRef
is a hook that returns an object with a current property set to the value passed to the hook.
For instance this:
const numberRef = useRef(0);
// numberRef is initialised as an object with a current property
Would return an object like so:
{current: 0};
// numberRef.current holds the value 0
It also provides a way for developers to interact directly with DOM nodes, outside of React’s management of the Virtual DOM. React describes this as an “escape hatch”.
We can use the ref
attribute of React elements to set the **current**
property to be the actual DOM node the element is rendered to. This way we can use the reference for old-school DOM manipulation adding event listeners etc.
const divRef = useRef();
/* divRef is initialised with current property set to 'undefined' because we didn’t give a value to the hook.*/
const MyComponent = (props) => {
return <divref={divRef}> A Div! </div>;
};
/* by passing divRef to the ref={} attribute, when the component is mounted to the DOM the divRef.current property gets set to the actual DOM node, eg. "<div>A Div!</div>" */
Can we use Old school Javascript DOM API in React?
Apparently, we can use the vanilla javascript DOM API in React as well because React eventually is just Javascript right?
But, will you ever use it when you have useRef?
Yes, there are some instances when you can’t refer to the elements i.e. selecting the element is not possible.
The following example of this polymorphism
Output:
Through WindBnb, now that you have climbed Mt. Everest, developing the same using a framework would be like climbing Mt. Fuji that would reduce the effort and ease the process by ten folds as observed in the above section.
Conclusion
Javascript is here to stay, it's not gonna go anywhere at least not any soon. Although, frameworks and libraries can change, come and go Javascript remains constant. Learning Javascript, especially when pursuing a career in the web is imperative. Hence, creating a real-time application in Javascript first helps a lot in understanding the core concepts better. Following are some of the concepts you need to know before getting into React.
- Callback functions
- Imports, Exports (Default, Named), and ES6 modules
- Map(), Filter(), and Find() methods
- Destructuring arrays and objects
- Rest and Spread operators
- Optional chaining
- Arrow Functions
- Asynchronous Programming
Thinking of becoming a React developer, I would recommend you to become a Javascript developer first which eventually makes you a better React/Angular/Vue dev more precisely a better Front end developer.
Want more insights and expert tips? Don't just read about Javascript! Work with brilliant engineers at Codemonk and experience it's effective use case firsthand!
Credits
A big shout out to the devchallenges.io platform and the creator of it Thu Nghiem. WindBnb is a part of a challenge in the front-end developer roadmap. Kudos to the platform, for the idea, and the UI/UX design.