WebDev Angela Udemy Notes
WebDev Angela Udemy Notes
WebDev Angela Udemy Notes
When you type a URL in the browser, it needs to map it to the IP address of that URL.
Browser - software that allows you to look up IP addresses, and receive data.
HTML
For documentation
https://devdocs.io/
CSS
- Everything in css is just a box, and we use the chrome extension 'Pesticide' to debug css code
- <link rel="stylesheet" href="style.css" /> is to be done in head tag of html to link them
- note that the link you make to the external css style sheet must me in the head section of the
html
- anatomy of css: selector { property : value ; } , example: h1{ background-color: blue; }
- 'tag selectors' are h1, body, img, etc
- 'class selectors' start with a '.', written as .class_name
- 'id selectors' start with a '#', written as #id_name
- difference between id and class: id can be used only for 1 element, whereas class can be
used for many together, AND , an html element can have only 1 id, whereas there can be
multiple classes
- valid: <h1 id="name1"> </h1>
- invalid: <h1 id="name1 name2"> </h1>
- valid: <h1 class="name1 name2" id="name3"> </h1>
- hover in css is a pseudo class written as :hover along with the html element (tag, class, id) that
you want to change hover properties of (let's you define the state of the css element).
- example: h1:hover{ … } , so this style is applied only when you hover over the h1 heading
Intermediate CSS
- Favicons: they also need to be linked in the 'link' tag in the head of the html.
- <head> <link ref="icon" href="css/fav_img.ico> </head>
- div is a content division element, and is used to group/divide the content on your website into
boxes.
- border-width, to specify, it follows the order: top, right, bottom, left
- the Box model of website styling
- each html element has this box model, which can be viewed in chrome developer tools
(inspect element). In the elements part of this tools, select the element like h1, div, etc, and the
corresponding box of that element shows up in the styles
- each Box has margin, border, padding and the content block
- Box Model has: Margin, Border, Padding
- The 'Display' property of css has 4 different values:
1. Block
2. Inline
3. Inline-Block
4. None
- Block elements take whole width of the screen
- Common block elements: paragraphs, headers, divisions, lists, list items, forms
- Common inline elements: spans, images, anchors
- we can change the 'display' property in css to make the element 'inline-block'. This means that
it allows multiple elements on the same line, as well as allowing us to change the widths of
these elements. [ display: inline-block; ]
- display: none; makes the element disappear. The other way to make an element disappear
from screen is to change the visibility option: visibility: none;
- To center align text, we first do 'text-align: center' for the body tag
- for other elements like h1, if you specify its width as 20%, now to centre align this block, you
need to specify the 'margin' property as ' margin: 0 auto 0 auto; '. The left and right must be auto
so it adjusts automatically to centre align that block of width 20%
- static: Default value. Elements render in order, as they appear in the document flow
- absolute: The element is positioned relative to its first positioned (not static) ancestor element -
- fixed: The element is positioned relative to the browser window
- relative: The element is positioned relative to its normal position, so "left:20px" adds 20 pixels
to the element's LEFT position
- static is the default position property used by css
- we can embed 'fonts' from google fonts by including them in the link
- to get icons and images: www.flaticon.com
- to get giphs: www.giphy.com
- font-size uses units such as: em, px, %, rem
- 1em = 16px = 100%
- rem is 'ripped em', which rips of all parent font sizes (and does not add them like em does)
- suggestion: use 'rem', out of all those
- float property: is used to wrap around text, for ex to display an image on the left followed by
text on the right (instead of having it on different lines)
- the 'clear' property acts as the opposite of the 'float' property.
Bootstrap
Web Design
JavaScript
- JavaScript is a scripting language, it tells the html elements to behave a certain way, just like a
script for a movie tells the actors to do what and when.
- JS controls the web
- JavaScript is an interpreted programming language, whereas Java is a compiled programming
language
- Inspect element -> Sources -> add index.js file : to add js on to the chrome browser
- Whereas a console is usually used to check line by line code, by testing it there.
- Most programmers use the console as a tool to help them “debug” (i.e., investigate and fix
problems in) their code, but you can also use the console as a way to just play around with
JavaScript
- alert("your message"); : alert is a function
- prompt is similar to alert, but it takes an input from the user.
- var name = prompt("Enter name: ");
alert("Hello " + name);
- camelCasing is used in JS mostly
- strings: concatenation(using + symbol) , string slicing,
- string has functions and attributes such as s.length, s.slice() (just like in python we do s[ : ])
, s.toUpperCase()
- var, function
- Math.round(x), Math.random(), Math.floor(x)
- === is equal to, !== is not equal to
- difference between var, let , const:
● const x = 10, now u can't change the value of x
● let x = 10, you can do x = 20, but you cannot do let x = 20 (cannot redeclare variable x)
● var x = 10, you can do both x = 20 and var x = 20.
● var declares the variable to be in global scope, whereas const and let define in block's
scope
● we generally use let and const (and don't prefer var)
- Math.random() generates a number between 0 and 1, and it's a floating number
- Google Chrome has an embedded JavaScript engine that runs all the basic commands,
hence we use inspect element and console to check our javascript.
DOM
- inline javascript: <body onload="alert('Hello');" >
- internal javascript: <script type="text/javascript"> alert("hello"); </script>
include this line in the body, at the bottom
- external js: <script src="index.js" charset="utf-8"> </script>
- Browser reads the html file from top to bottom, hence we put the css in the head, and the js in
the end of the body after all the html body elements
- The task of converting an html file to a DOM (Document Object Model) is done by the browser,
when you load up the webpage.
- document.firstElementChild.firstElementChild : gives the 'head' section of the webpage
- document.firstElementChild is the 'html'
- document.firstElementChild.lastElementChild is the 'body' section of the webpage.
- so the objects inside DOM can have properties and methods.
- document.querySelector("h1") allows you to select all the h1 in the DOM,
document.querySelector(".class_name") allows you to select all the classes with this name.
- hence querySelector allows you to select specific parts of the document DOM.
- The querySelector() method only returns the first element that matches the specified
selectors. To return all the matches, use the querySelectorAll() method instead.
- Changing HTML elements:
● element.innerHTML = new html content: Change the inner HTML of an element
example: changing the h1 tag name to something else
● element.attribute = new value : Change the attribute value of an HTML element
example: .src attribute of an image
● element.style.property = new style : Change the style of an HTML element
to change the css properties
- Finding HTML elements:
● document.getElementById(id) Find an element by element id
● document.getElementsByTagName(name) Find elements by tag name
● document.getElementsByClassName(name) Find elements by class name
● document.querySelector() : this allows you to select elements the way you do in
css, example: #title for an id, .cards for class, and you can also specify multiple
combination of selectors like you do in css (for hierarchy of specifying one element)
- note that getElementById() returns a single element, whereas getElementsByTagName() and
getElementsByClassName() returns an array.
- to change the css properties using javascript, we use .style.property , but note that the
property names are camelCased in javascript.
so in css if we have font-size or background-color, in js we have fontSize and backgroundColor.
- document.querySelector("h1").style.fontSize = "20rem";
- in javascript, the values you set these style properties to must be specified in strings. Like
above, "20rem", and not just 20rem.
(unlike in css where you did not need strings)
- document.querySelector("button").classList : returns the list of classes that this html item
has. The returned list is of type DOMTokenList
- To add elements to the DOMTokenList, we use the 'add' method, and to remove, we do
'remove'.
- To change the text in the html using JavaScript:
● document.querySelector("h1").textContent = "<em> Good </em>";
this makes the h1 heading to <em> Good </em>
● document.querySelector("h1").innerHTML = "<em> Good </em>";
this makes the h1 heading to Good
so .textContent only modifies the text content between the tags, whereas the innerHTML also
allows you to change the html tags etc as it accepts the entire html code as the string.
- document.querySelector("a").getAttribute("href");
- document.querySelector("a").setAttribute("href", "www.google.com");
- document.querySelector("button").addEventListener("click", func_name);
- note that the second argument of the addEventListener() method is just the name of the
function. Hence we don't call the function there as func_name(), we only mention name
- you can debug in chrome developer tools using 'debugger;'
- write debugger; followed by the function you want to debug, and it will run through each step
and display along the way.
- breakpoint is an intentional stopping or pausing place in a program, put in place for debugging
purposes.
- callbacks in javascript are used to pass one function into another function in js. In javascript,
functions are objects, and objects can be passed to functions as arguments.
- let myAudio = new Audio("drums.mp3"); will create a new html media element, and store it in
myAudio. Then to play the audio, you can do myAudio.play()
- inside the eventListener, the keyword 'this' helps us refer to the object that triggered the event.
- Objects are variables too. But objects can contain many values. The values are written as
name : value pairs (name and value separated by a colon).
- var person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};
- objects in js are created using similar syntax to dictionaries in python.
- the only difference between calling constructor function vs any other function, is that
constructor function uses the word 'new' to create new objects, and that its name's first letter is
capitalized.
- Higher Order functions are those functions that can take functions as inputs.
- x.addEventListener("click", function(event){
console.log(event);
});
- the above log would print MouseEvent, which was the event that triggered this event listener.
- Hoisting in javascript means that the vars and functions are hoisted to the top of the js file.
This means that even if you have declared and defined the function below/after calling it, it
would not give an error since the declaration has been hoisted to the topmost/first, hence it will
not feel like it has not been defined yet.
- setTimeout() method allows you to execute a function after certain amount of time has passed
- setTimeout(function(){console.log("now")}, 2000); is correct
- setTimeout(console.log("now"), 2000); is wrong
- this is because the function() should not be called in the declaration itself, hence we should
only give the name of the function as the second argument, and not call it instead.
- The most popular OOPs model is class-based. But javascript isn't class-based, it is
prototype-based.
jQuery
Animations in jQuery
- .show(), .hide(), .toggle(), fadeIn(), fadeOut(), fadeToggle(), slideUp(), slideDown(),
slideToggle()
- This .slideUp() and .slideDown() can be very useful when you deal with drop down lists.
- jQuery also allows you to do custom animation using the .animate() method, like this:
- $("h1").animate({margin : 20rem }); this will gradually change the margin to this value,
note that you can only change numeric properties in this animate method
- you can chain multiple of these animations together,
$("button").on("click", function(){
$("h1").slideUp().slideDown().animate({opacity : 0.2});
});
- Inside the handler, you can use the keyword this to refer to the button object that triggered the
click. So sometimes you use the 'this' object, whereas sometimes you use the 'event' which we
pass as the argument to the function.
Nodejs
- Nodejs allows us to use javascript for our backend too.
- Websites such as Netflix, Uber, Twitter all use node js.
- Node Js allows us to take js out of just the browser, liberating it to interact with the hardware of
the computer (and not just be trapped with the browser like how we saw till now for front end
javascript)
- So nodejs allows you to run and execute javascript code on the server
- In the terminal we write 'node index.js' , this command means that we use node to execute
the file index.js. And the contents of the index.js which are inside console.log() will get logged to
your terminal.
- Node REPL(Read Evaluate Print Loop) allows you to write line by line js code and execute it
each time you press enter, very similar to the chrome developer tools interface you did in that
console.
- so to use node repl, just type 'node' in the terminal, and then you can execute javascript
commands line by line.
- The 'fs' module provides an API for interacting with the file system, and whenever you need to
use a node module, you write 'require' in your js file.
- fs.copyFileSync(src_file_name, dest_file_name);
- builtin require function is the easiest way to include modules that exist in separate files. The
basic functionality of require is that it reads a JavaScript file, executes the file, and then
proceeds to return the exports object.
- hence this require() function allows you to import/use other modules (pieces of code), that
exist in separate files. But to use pieces of code that other people would have written that's not
in these modules that you get when you install node, we use npm
- so node is a runtime environment that allows you to run and execute javascript code outside of
the browser, and in your local machines and on servers.
- npm is: node package module.
- to initialize your own package do 'npm init' in the terminal, and this creates a package.json
file in that folder which is a json file with metadata.
- The other important aspect of a package.json is that it contains a collection of any given
project's dependencies. These dependencies are the modules that the project relies on to
function properly.
- By running an install command (npm install) inside of a project, you can install all of the
dependencies that are listed in the project's package.json
- npm install <module> In this command, you'd replace <module> with the name of the
module you want to install. For example, if you want to install Express (the most used and most
well known Node.js web framework), you could run the following command:
npm install express The above command will install the express module into /node_modules
in the current directory.
- Whenever you install a module from npm, it will be installed into the node_modules folder.
- the command 'npm install' will install all the dependencies listed in the package.json file of that
directory, whereas the command 'npm install express' will install the node module called
express.
- so package.json is a description of all the packages so far ( and the dependencies )
- so whenever you install something using 'npm install <module name> ' , the "dependencies"
field is added to the json file which now contains this module as a dependency.
- We previously did 'require("fs")' which was using an internal nodejs module, and now after we
installed a module express, we can now 'require' it in the same way we did for the other node
module such as "fs".
Express
- Express is a node framework
- Like jQuery is to javascript, similarly express is to node.
- so express is a framework, or a bunch of code that someone else wrote, that adds extra
features and helps to organize and structure your code.
- Express was built to help you write less repetitive code when you're building web applications,
and is made specifically for web developers.
- To create a real server locally on our computer using nodejs and express.
- to use the keyword const for 'const express = require("express")', we need to write a hint to the
linter as //jshint esversion:6
- const app = express(); : this is a function that represents the express module, and we bind
that to the word 'app'.
- app.listen() : listen is a method which tells it to listen to this port where any http requests get
sent to our server. A port is basically just a channel we tune our server to.
- In every home, there is one mailbox and multiple people. The mailbox is a host. Your own
home mailbox is a localhost. Each person in a home has a room. All letters for that person are
sent to his room, hence the room number is a port.
- Just as the IP address identifies the computer (on the TCP/IP network), The network port
identifies the application or service running on the computer.
- so, ports allow different applications to run on the same machine (each listening) at different
ports.
- Socket is a combination of IP address and port. [ socket = IP address + port ]
- Ports are a way of uniquely identifying each application on that machine. Hence when we
make a request (here we are clients), to the server of google.com, it goes to the corresponding
IP address(which it obtains from DNS), and then to access 'which' application on their server,
the port number also needs to be specified (which in most web application cases will be 8080).
- When we do app.listen(3000) we are asking the server to listen at the port number 3000. To
see what it is listening, we can use applications such as 'telnet' or the 'chrome browser', which
are also clients which will send requests to this port and give us information of what is going on.
Multiple clients can talk to the server at once.
- Now to get our server up and running, we write app.listen(3000) in the js file. Once we run this
file, we have a server up which is listening on this port 3000. Now, to check if it is listening
properly, we can use 'telnet' by opening another terminal window and the command
'telnet localhost 3000' which connects to the local host at this port number.
To do the same thing using the chrome browser application, type 'localhost:3000' in the bar, and
it allows to analyse the same thing (just like telnet is an application that connect to the 3000
port)
- so note that, when we ran 'node server.js', we got the server running because of the line
app.listen() in the server.js file. Now, once the server is up and listening, we need to be able to
connect to our server through an application, which here is the chrome browser where we
specify localhost:3000 (this can be done using the telnet application too, using the command
telnet localhost 300, which allows us to do the same thing through the terminal)
- now we need to write code so that after we make the port listen, we need to handle what it
does after a client connects to it, what response it will send for what type of requests.
- app.get() is a method provided by express which allows us to specify what should happen
when a browser/client gets in touch with our server and makes a get request.
- "/" means that the request is being sent to the root of the website/server.
- A URI (Uniform Resource Identifier) is a sequence of characters that identifies a web resource
by location, name, or both in the World Wide Web.
- So when we use the chrome browser and specify the URI as 'http://localhost:3000/contact'
which means that we are using the chrome browser to make a request to the server listening at
port 3000, at the route '/contact'. Here, the chrome browser provides us the 'http client' which
sends a 'http request' to the server listening at port 3000. This 'request' can be get/post/
anything else, and this is interpreted by the browser here and sent as a http request to the
client. Then this function() of ours as the second argument handles and responds to the request
accordingly.
- Note: ^C (Ctrl + C) kills the server, whereas ^Z only stops the server (it does not kill it, which
means its still listening at that port, and hence the next time you do node server.js, it gives an
error that someone else is already listening at that port).
Hence always do ^C to kill servers (and not ^Z)
- If you did ^Z by mistake, then to get back the process to kill it, type in the terminal 'fg' which
brings up the jobs currently running in foreground. Then you can do ^C after that. To see all the
running jobs at the moment, write in the terminal 'jobs'.
The jobs command displays the status of jobs started in the current terminal window
- Everytime we make changes in the code, we need to save the .js file, bring down the server,
and then rerun the server each time. To avoid this, we use 'nodemon', so instead of doing 'node
server.js', we instead run 'nodemon server.js'. So everytime we save the .js file, nodemon
restarts the server automatically
Hence, use 'nodemon server.js' to run the .js file and to make the server listen to that port
continuously.
- Till now we saw the .send() api provided by express, now to send an entire file as a response,
we use the .sendFile() api. This method takes the path of the file you want to render which in
our case is the index.html file.
- If you just do response.sendFile("index.html"), this will work now since the server is hosted on
my local machine itself. But when you deploy it later, it will be hosted on the cloud (someone
else's computer), so the files absolute path will change and this won't work. So, we shall specify
full path correctly using __dirname which gives the current directories path
=> response.sendFile(__dirname + "/index.html");
- To be able to deal with the data posted by users using the html forms, we need to use another
node module which is 'body-parser' (just like we installed the express module). So just do 'npm
install body-parser', and then it comes as a dependency in your package.json file. Now just
require() it in your .js file.
- So to use body parser, do app.use(bodyParser.urlencoded({extended : true}));
- we use .urlencoded() whenever we are dealing with data collected from forms.
- now inside the callback function of the post method, we can use request.body to access all
contents obtained from the form. If the name field in the form was num1, then we access it as
request.body.num1
- the 'action' field in the 'form' specifies where it would submit the form, in our case "/", hence it
submits to this route, and hence the post method for this route will handle this case.
- note that request.body.num1 is a text field, and if you want to convert it to a number, just do
Number( request.body.num1 );
- Note that this code is running on the backend, the server side, and the client/browser knows
about none of this.
APIs
- APIs (Application Programming Interfaces) is a set of commands, functions, protocols and
objects that programmers can use to create software or interact with an external system.
- we have used jQuery APIs which were methods provided by jquery such as .add(), etc which
made our code writing much shorter and smaller. Hence these are also APIs (as they allow
programmers to use them to create software).
- Tinder uses facebook's APIs to show information like 'shared' friends, etc. This is 'interacting
with an external system'.
- Here, we focus on APIs that allow us to interact with an external system (most importantly, an
external server). So the external system has exposed APIs, using which we request data from
their servers.
- So API is like a menu which tells you about what are all the things you can do with their
services. And to be able to interact with their data, we need to use these APIs which they
exposed, like a weather website which exposes APIs about weather forecast to get temp, etc.
- https://sv443.net/jokeapi/v2/
checkout this website for jokes, and it provides joke APIs to get a random joke.
- So when I make this API call: https://v2.jokeapi.dev/joke/Any?format=txt&type=single
So this is the exact URL at which we are sending our request (from the chrome browser since
we put this url in the chrome tab). Here, the endpoint is the part till 'https://v2.jokeapi.dev/joke'.
- But we need to specify a specific path after the endpoint, here '/Any', where /Any is the route,
and this API endpoint specifies exactly from where it will get data from that server. So, here we
are making a get request.
- So here, the endpoint is: https://v2.jokeapi.dev/joke
- And to complete the path of the url, we need to specify: '/Any'
- So the Path here is: https://v2.jokeapi.dev/joke/Any
- To allow the API to be flexible to deal with flexible queries, APIs allow you to provide
parameters. The URL Parameters go at the end of the url after a question mark '?'. And these
parameters are specified by a key-value pair separated by an '=' equal to sign.
- https://v2.jokeapi.dev/joke/Any?format=txt&type=single
So after the '?', we specified the parameters, that we want format to be equal to txt, and the type
to be equal to single. So to specify more than one parameter, each parameter is separated by &
symbol.
- So, through the use of paths and parameters, we are able to specify the API more specifically.
All these parameters are basically for the 'get' request which we are requesting from the joke api
server. (Note: this is still a get request, and not a post request).
- So these formatted URLs allow us to make these API requests to those servers easily from our
browsers.
- Authentication
Through the API, they (the servers / api providers) have to be able to identify you as the
developer and they have to keep track of how often you are using their server to get data, and
then charge you or limit you accordingly.
- The weather APIs website is: https://home.openweathermap.org/
- When we sign up, we get a unique API key, which is an id that the server uses to uniquely
identify you, and keep track of how many requests you are making
- The format to make API calls to this weather server is:
api.openweathermap.org/data/2.5/weather?q={city}&appid={API key}
Here it takes 2 parameters which are city name and the API key provided when you had signed
up.
- Also, to understand how the same url shows your account / another person's account for them.
This is done using cookies. So, the first time you sign up, a cookie (for ex in the format of a jwt
token will be sent to you/client from the server), which will be used to uniquely identify you the
next time you make any requests to the server. So basically, the next time when you make a
request to the server, the cookies are also sent as part of the request which the server uses to
identify (by verifying the cookie/jwt token with what it had sent to you) that it is you who made
the request.
- Hence these cookies help you stay logged in, without having to re-login every single time.
- These APIs are returning the request in json format. To easily understand json format, we can
use chrome extensions that allow us to do so.
- The order of specifying parameters (separated by '&') does not matter.
Postman
- So far, we have tested APIs using the chrome browser by typing the whole url with specifying
the endpoints and the parameters. This can be prone to human errors while typing this whole url
out, since it's hard to see where each parameter ends and the new one begins.
- Hence, while testing out our APIs, we use a tool called Postman.
- So basically, just as our chrome browser is a http client, similarly postman is also an http client.
(that allows you to make these requests and api calls in a more visually formatted way)
JSON
- JSON is JavaScript Object Notation. It looks very similar to a javascript object, and hence this
name. The difference is that when you create an object in javascript, when you make the
key-value pairs, the keys are never strings, whereas in json, keys are always "strings".
- JSON format is extensively used to transport data over the internet, because it's very readable,
and it can be easily compressed to a string and transported, and then recompressed later at the
other end too.
- Other such formats are XML, HTML, JSON
- Now we want to make a project that displays the weather data using the weather APIs
provided by openweather.org website.
- So our structure flow looks like:
- So we need to be able to get data from this external server (here the weatherapi.org by using
their apis). To do this we use another node module called 'https'. The https node module is a
native node module hence doesn't have to be installed every time like we had to do for the
express module.
- Hence, we can use the https, a native module of node, to make get requests to external
websites (it performs a get request across the internet using the https protocol).
- The 200 (OK), 404 (Not found) are the HTTP Status Codes, and using this https module, we
can print them as, console.log(requestFromHttps.statusCode);
- Some common http status codes you'll come across are:
● 200 : OK, means that everything went find, and your request was made successfully
● 404 : Not Found Error, means that the path you specified is wrong since that url/endpoint
does not exist
● 401 : Access Unauthorized (unauthorized http request). This is the error you could face
when you entered the wrong API key, whenever you deal with such authentication using
servers.
- JSON provides two methods to compress and uncompress your data, which are:
● JSON.parse() : to uncompress the data, and returns a javascript object
● JSON.stringify() : to compress your javascript object to a string.
- We get hold of the data using the response.on("data", <callback function here>); using the
.on() method.
- The data we got was in hexadecimal format, hence we used JSON.parse() to convert it to a
javascript object.
- Note: You can have only 1 res.send() in any of the app.get() methods, else it will crash.
- So in order to be able to send multiple lines to the client as a response, we use
response.write() method. We can have multiple response.write("...your text…"), and eventually
just do 1 response.send();
- If you do .sendFile(__dirname + "/index.html"); this will show the html page, but it won't be
able to use the "style.css" or the images specified locally inside this because it doesn't have the
relative paths to those files.
- So to do this, make a new folder, let's call it "public". Now inside app.js, add the line (which is
express code to allow you to use these static files), app.use(express.static("public"));
- Now all the paths that you specify for static files (of images and css styles), you can specify
them wrt this folder "public".
- In the weather API project, we only sent a get request to the external server to retrieve data
from them (so we just used https.get()). But here, in the mailchimp project, we need to post data
to their servers, so we use https.request(url, options, function(){});
response.on("data", function(data){
console.log(JSON.parse(data));
});
});
request.write(jsonData);
request.end();
To send data to the external servers, we just use request_name.write(), and then the .end()
- The data sent back by all these external servers using their APIs is usually binary/hexa when
you receive it in this 'data' field. Hence, always do JSON.parse(data), to convert it to a
javascript object, which we can use.
- The Procfile is the file that Heroku uses to know how to start our file. So inside the Procfile, we
specify the command it needs to execute to get our app running, which in our case should be,
web: node app.js
(Note that Procfile must be named exactly this, and not procfile or Procfile.txt, etc)
- So before deploying to heroku, remember to make the following changes in your project folder:
● In the app.js file, change the local port 3000 to: process.env.PORT || 3000
● Add the Procfile, and inside it write: web: node app.js
- Steps to deploy on your heroku after you have made an account on heroku: (In the terminal do
the following steps, very similar to what you would do for pushing code to github)
1. git init
2. git add .
3. git commit -m "first commit"
4. heroku create (this would create a link at which your website is hosted)
5. git push heroku master (very similar to how you would push code to github)
The next time you make changes, etc. you just have to follow the same steps starting from git
add . and then it will get updates on the live website too!
- Working directory is the one where you first do git init to initialize your repository in that
working directory.
- Staging area is where you stage and add files before committing. Why have a staging Area,
and not directly commit to local repo? Because sometimes there might be certain files that you
don't want to commit (files that you don't want to track), so you stage them, hence you dont add
them, hence they are the untracked files.
- So the staging area is a good place for you to know what the file you want to ignore (untracked
files) and what are the files you want to track.
- To view changes in a file, use the command: git diff chapter3.txt
It shows the difference between the current file's contents and the latest committed files
contents, and shows the added and deleted contents in the file.
- git checkout chapter3.txt will rollback to the latest committed version of that file, hence it
brings back that version of the file which was at the last checkpoint when you had committed it.
- Now to push up your code to something like github, first make a new repository in github. Then
we execute the command:
git remote add origin https://github.com/geegatomar/Learning-Git-Angela.git
which basically pushed my locally committed changes to this remote repository on github. This
basically tells my git that I have created a remote repository somewhere on the internet and I
want to transfer all of my commits over there.
- the remote repository here, we have named it as 'origin'. We could have named it anything
else, but this is the standard convention to call it 'origin'.
- git rm -r --cached .
Here, --cached tells it to remove those files from the staging area (it's currently cached in the
staging area).
And the -r option is to specify recursively, ie. to remove files and folders inside directories (it
recursively removes directories inside directories. Note that -r is rm's option, just like you do rm
-r to remove any folder from the terminal). If you don't want to rm all the cached files from the
staging area, you can specify the exact files. And when you specify the exact files, you would
not have to do -r (since it's not a directory that needs to be recursively removed).
- So, another way to do this would be using 'git restore' as (to unstage those files):
git restore --staged <file_name>
- If you have committed a file (ie. the file is now in the committed Local Repository stage), and
you want to go back to an older commit. Note that git commits are atomic (immutable entities),
so you will deal with the commit as a whole, you can't just choose to revert back one particular
file (this is an important concept to understand that git deals with commits as a whole, i.e.
commits are atomic in nature).
- So to go back to a previous commit (i.e restore back to one of your older commits), you first do
git log to see all the commits you have made till now, and then use 'git reset' to revert back the
state to a previous commit. To do git reset, you could either do:
git reset HEAD~1 , where you specify how many commits back you want to go.
For ex, if you want to go to the third last commit, you do: git reset HEAD~3
You could also do this using git reset <hash_key>
for example: git reset e364451ccb1f7e8feca9329da0270697b1527773
- And note that all the commits in between will then be lost after reverting back to this previous
commit.
- There's another thing called 'revert', in which you can revert a particular commit. So on doing
this, it reverts that commit by creating a new commit with these changes in it.
git revert <commit_id_also_called_the_hash>
Cloning
- To clone someone else's repository from Github to your local machine, just execute the
command
git clone <url_of_the_repo_to_clone>
- Then you have their repository locally, and if you do "git log", you can see all the history of
commits made by people.
Branching and Merging
- Multiple people might be working on different features of the project, and hence each of you
work on different branches, and you merge it with the main master branch only when you know
that all your changes are correct.
- The red thing here which is "origin/master" shows the latest branch that is committed to Github
- The 'HEAD->alien-plot' shows the latest commit I have made in the current branch.
- To merge another branch with my master branch:
● First go to the master branch, git checkout master
● Then merge the other branch, git merge alien-plot
- After merging, all those commits made on the other branch will now show up in the master
branch, and even the merging step is added as a commit.
-- Forking is different from cloning because,
In forking, we just create a copy of someone else's remote repository and bring that copy to our
github now. Then, to be able to work on that remote local repository (the copy, which is now
under my Github account), we need to clone it. And then we have it in our local machine (only
after cloning it), and then we can add/edit code. Then upon pushing this code, it goes to the
remote local repository of mine (the one that I cloned), and only if you make a pull request, only
then you will be able to add these changes from your forked Github repo to their original github
repo.
-- So, there are two options of getting someone else's remote repository to your local machine
for you to work on:
After cloning to your local machine, you We first fork the repo and obtain a copy of
directly push to that repo from which you that original repo in our Github account. Now,
cloned from. But, if you don't have access to we clone to our local machine after which we
that repository to push, then when you do 'git can add/edit code. Then we do 'push' to our
push', it will give an error. Github (which is a copy of the original
someone else's repo). Note: Here we are
able to push because we are pushing to our
own Github, to which we have access. After
this, from sending code from our Github
account to their Github account (from where
you had forked), we make a Pull Request.
This is called a Pull Request, because we are
making a request for them to pull and accept
our code. It's their repo and they have the
charge and control over this.
- So forking basically brings code/projects from someone else's Github account to your GitHub
account. To be able to edit and add to that code/project, you will have to anyway clone it, which
will bring the code to your local machine after which you are free to do whatever you want.
- Forking: Brings from someone else's Github to my Github
- Cloning: Brings from Github to my local machine.
- Forking is basically making a copy or duplicate of someone else's remote repository, and
putting it under your own Github account.
- So, if you are added as a collaborator under some project, then you have write access to the
project, so you can just directly clone and then push to this repo. But in most cases (when
dealing with Open Source projects), you won't have this access, so you first need to fork, and
then clone to your machine, then push to your Github, and then make a Pull Request to the
original remote repository on GitHub (from your Github account)
- This is a very standard way to begin your 'app.js' file with, hence you can always begin with
this template. (since you're most likely always going to use express and body-parser modules).
- We need templating (for our html files), when we need to create html files that have very
similar content.
- ejs is one of the most popular ones that node developers use.
- to install it, like any other node module, just do: npm install ejs
and then require() it inside your app.js file. And add this line to tell you app to use ejs.
app.set("view engine", "ejs");
- This line tells our app to use ejs as its view engine.
- We then use the res.render() method which uses the view engine that we set up above to
render a particular page.
- The first argument is the page you want to render. Here, it's the 'index.ejs' page. These .ejs
files must be in a folder called 'views' folder. The ejs view engine will look for these files in this
particular 'views' folder.
The 'view engine' by default looks in the 'views' folder for files to render. So all these .ejs files
which you want to render, must be in the 'views' folder.
- The second argument is a javascript object. The keys are the variables that you will use in the
index.ejs file. And the value is the value you want the .ejs file template to replace it with.
- The .ejs file is written exactly like an html file, except that you use the ejs syntax to use those
keys of the javascript object that res.render() gives.
The syntax for this ejs templating part is: <%= %>
<%= theJavascriptObjectsKeyName %>
So this acts as a marker for ejs, and tells it that this is where you have to place the particular
variable's value.
We put in the variable name that we want to replace that marker with.
And the ejs file will replace this key with its corresponding value. So, this in a way allows you to
send data from you app.js file to the html files (here, we are sending to the .ejs file which is
exactly like javascript, except for the additional functionality of <%= %> hence we use ejs for
templating our html files).
- To use control statements in .ejs file, like using if-else statements, we use the scriptlet tag of
ejs, which is written like <% %>, must see official documentation for this information. So if you
define any logic in javascript, you will have to add these scriptlet tags around each of those
lines. You must add these on 'EACH' of the lines, as they work on a line by line basis.
<% for(var i = 0; i < itemList.length; i++){ %>
<li> <%= itemList[i] %></li>
<% } %>
So, we basically first write out our logic part (if, else, for) using javascript, and then for all the js
parts, we add scriptlet tags on each of the lines as enclosed between <% %>, and leave out the
html part, i.e. don't put any ejs scriptlets for the html lines as shown above here.
- Sometimes instead of writing your res.send() or res.sendFile() or res.render() again, you could
just redirect to another route by saying res.redirect("/");
Scope of Variables
- Scope of local variables (variables inside a function) is limited to that function.
- So in javascript, you can create variables using var, let, const.
- var and let behave slightly differently in terms of their scope:
- Make sure to create a folder with the name "public", into which you move all your css folders,
images folders, etc and all these static files.
- There are multiple ways of declaring a javascript function, one of which is declaring an
anonymous function and setting is equal to the variable with a name, ex:
var my_func = function(){
};
It's the same as doing
function my_func(){
}
- Also note that module.exports can also be shortened and written as just exports
- When we clone someone else's node repo, it will not contain the node_modules folder, as they
would have gitignored it. But all the dependencies would be mentioned in the package.json . So
after cloning, all you need to do it to run the command npm install
on the terminal and then npm will go through the package.json and install all those necessary
files that are required for this project.
- the command 'npm audit' tells you the vulnerabilities.
- To add multi-line input in html, we don't use 'input', instead we use something called 'textarea'
which we use for multi line input.
- Another way to loop around an array (without the for(var i = 0; i < arr.length; i++)...), is to use
the forEach() method in javascript.
- so, the forEach() javascript code will look like:
array.forEach(function(each_element){
console.log(each_element);
});
- While nodemon is running, to restart the server, type rs in the terminal while nodemon is
running.
- camelCase vs kebab-case
The two most used cases in javascript programming.
Lodash
- Something that developers use a lot with Node is called Lodash.
Lodash is simply a utility library that makes it easier to work with javascript inside your Node
apps.
- To require lodash, the convention is to use an underscore (a 'low dash _')
var _ = require("lodash");
- We use _.kebabCase();
Databases
- Depending on the type of data you want to store, and the structure of the data, you choose a
database over another.
- Two main types of databases
SQL (Structures Query Language) and NoSQL (Not only Structured Query Language)
- The most popular databases when working with Node are:
● For SQL: MySQL, PostgreSQL
● For NoSQL: mongoDB, redis
- NoSQL uses JSON objects to represent your data, whereas SQL uses tables. Hence SQL is
inflexible.
- NoSQL is more flexible and when your data structure is not predefined you can use this as
you're not bound to a particular structure, and can flexibly change it later very easily.
- SQL databases are very good at keeping relationships in your database, hence called
relational dbs, whereas NoSQL are non-relational dbs.
- Example comparing SQL and NoSQL for the same data and use case:
SQL NoSQL
In SQL, we can make separate tables for each of the Customers, In NoSQL, there are no tables or relations,
Products, and Orders. And then we can establish relationships hence each order is represented as a
between them, and when we need data that spans over multiple document, and we use embedded objects
tables, we just use joins. for the keys customer and products.
This would lead to data repetition.
Hence, depending on the structure of your data, you will have to choose your database.
- When you have a lot of relationships amongst data, SQL is a better choice for a database to
go with.
- However, if your use case is having a lot of one-to-many relationships (for example,
instagram's single user has data like name, id and multiple posts. So each user has an array of
posts.) So when you have a single user generating a lot of content, here it's one user to many
posts, then it's much easier to use mongoDB
- One of the reasons to use NoSQL over SQL is scalability (SQL gets slower and slower as your
data sets size increases).
- Because of the way mongoDB organizes its data into smaller chunks/documents of, where
each record or row is represented as a JSON object. So this allows for a distributed system and
so your database can be distributed over multiple computers.
- Hence SQL is better querying for complex relationships (that span over multiple tables).
- MySQL databases scale vertically hence requiring more infrastructure and expense (hence
difficult to scale). Whereas, NoSQL scales horizontally and hence this allows for a
distributed system and your database can be distributed over multiple computers, hence
easier scalability.
Summary of Comparing the two most famous SQL and NoSQL databases.
- With every database there are 4 main operations (CRUD) you will perform:
● Create
● Read
● Update
● Destroy
- Whenever you learn about a new database, always first wrap your head around how you will
perform CRUD operations in this db.
- run the command: mongo , to get mongo client started
- When it opens, you see an angular bracket, and then you can enter the command 'help', and it
will give you all the list of commands you can execute there.
- To create a database, the command is: use shopDB
- To check the current database which its using, command is: db
- Collections in mongodb are similar to tables in the SQL world. They are a collection of
documents. And a document is simply just a single data record (like in SQL).
Note: Whenever you use mongo locally, you need to get the mongod server up and running,
which is the mongod server. And then to use the mongo client, we run the command 'mongo'.
To Update
- Similar to the query/res, the syntax for this is:
db.name_of_collection.updateOne(query, update_action)
- For example:
db.products.updateOne({id : 1}, {$set : {stock : 32}})
To Delete
- db.collection_name.deleteOne(query, projection)
- So each document in mongo is a javascript object, and a collection of these objects together
make a collection.
-- And note that in most of these mongo functions, there are 2 optional parameters. Of which the
first parameter is the query part where you specify the 'where' condition, and since this is a
javascript object, we use embedded objects to write this 'where' condition.
The second parameter specifies to which columns/fields you want this operation to be applied
on. (In SQL this is the part where we would have done select col1, col2, col3).
- When you are creating a Node app that needs to connect to a Mongodb database, there are
essentially 2 options for you to choose from:
● Native MongoDB Driver
● Using an ODM (Object Document Mapper) like mongoose.
The most popular way of working with mongodb when using node is by using this
package called mongoose.
Mongoose
here we are telling mongoose to establish a connection and connect to the server listening at
port 27017. (before doing this we must start the mongod server from the terminal by running in
the terminal the command: sudo systemctl start mongod). So the line
"mongodb://localhost:27017" means that the type of protocol we are establishing is 'mongodb
protocol' (just like if we had http protocol we would have written 'http://...') and then the IP
address which here is using local host, and then the port number which here is 27017.
- So in this case, the client is the mongodb driver itself (which you got by installing from npm, the
mongodb module), and then mongoose is just a tool/package that makes it shorter and easier to
write code which you would have to otherwise have written for mongodb's package directly.
(This is just like how jQuery makes writing javascript code shorter, similarly mongoose makes
writing mongodb code easier).
- In mongoose, we first create a schema (note: this is flexible and not supposed to be followed
strictly like we need to in SQL)
const fruitSchema = new mongoose.Schema({
name: String,
rating: Number,
review: String
});
fruit.save();
- then doing .save() method on the document saves this fruit document into a fruits (Fruit)
collection inside our fruitsDB. These 3 steps are basically what comprises our Insert command.
- Now, to do a find and search for the fruits inside the Fruit collection,
Fruit.find(function(err, fruits){
if(err){
console.log(err);
} else{
console.log(fruits);
});
- This callback function takes error as the first argument, and the fruits collection as the second.
- Data validation in mongoose is much simpler compared to doing it in using a pure mongodb
data driver (in which we had to multiple assert statements).
- Mongoose has these builtin data validators which you can provide while creating the shema,
so you can specify for an attribute, say for the rating of the fruits:
rating: {
type: Number,
min: 0,
max: 10,
required: [ True, 'You must specify the rating!!']
}
- To delete, we do .deleteOne()
- Read the mongoose documentation for all the methods in detail (under the 'Queries').
- Note that while working with any new db, the first important thing is to understand how to
perform CRUD operations in this db.
mongoose.connect("mongodb://localhost:27017/todolistDB", {useNewUrlParser
: true, useUnifiedTopology : true});
The first argument has the following components (and their meanings):
● mongodb:// Here mongodb is the protocol establishing the communication
between the client and the server (like we saw http previously).
● localhost This is the IP address of the machine
● 27017 This is the port on which the mongodb server is connected to and
is listening at
● todolistDC This here refers to the database. If it already exists, that will be
used. Otherwise it will create a new one.
Synchronous vs Asynchronous
- Javascript at its base is a synchronous, blocking, single-threaded language. This means that it
reads through the code line by line from top to down executing one operation at a time (just like
all languages do).
- But, javascript is special and since it's used in multiple operations such as loading contents to
a website, or reading from a database, etc. it cannot wait till one that operation of getting data
from database executes, since that might take time. And javascript needs to be fast, especially
websites need to be quick, hence in such cases javascript behaves asynchronous.
- So, if a statement in the code is doing a find from a db, js will create a new thread for this, and
continue with the statements that follow (the ones that are after this).
- This asynchronous nature of javascript is also to support callback functions in js which are very
widely used.
- Hence if you want a piece of code to be executed only after another piece, you will have to
write it inside that same callback and nest these inside one another (because if you don't, then
you will write is after this statement, which due to the asynchronous nature here will not be
executed in the desired order).
Code:
Output:
Important example
- The first statement encountered is for a db fetch, which it goes to do. And since js is
asynchronous, it will not wait for the db results to come back. Instead it will continue with the
next statements that follow.
- The setTimeOut function will execute its callback only after 3000 ms, but it will continue to do
the next statements after it.
- The next statement is the console for 'This is after timeout function'. Hence this is printed out
first. And then the db statement finishes its fetch, after which it console logs 'Inside function'.
And then, after 3000 ms are over for that Timeout function, it will console log its contents which
is the 'Outside function'.
- Hence, notice in this code, we wanted to do the render function only after it got back contents
from the db, we had to nest it inside that db fetch function itself (because if we wrote it outside
after it, then it would get executed earlier as seen due to its asynchronous nature here).
- This is one way of making sure your code is consistent and behaving as expected. But this
nesting might lead to unreadable code. Hence there's another way to specify that you shall
execute a block of code only after another is by the use of 'promises'.
- Watch this for reference (for asynchronous js):
https://www.youtube.com/watch?v=PoRJizFvM7s
- Express uses route parameters and allows us to create dynamic routes.
- When you want to use the value from the forms that were posted/submitted, we use body
parser for that, and tap the values using: req.body.name_of_input_in_form
- If we need to pass more stuff, we can also assign values to other html items like buttons, etc
and then again tap their values using the name that we assigned to the button.
- In cases when there are no other html elements, we can use an input html element with a
special type="hidden", which is just solely used for this purpose, i.e. to pass values from the
html to the js and being able to tap those values from js.
- Like we used Heroku to deploy our Nodejs server, we need another such server (on the world
wide web) which can hold our database.
- Mongodb provides its cloud services called MongoDB Atlas.
MongoDB Atlas will host our database and serve up the data whenever it's needed. So, our
nodejs will be able to make necessary requests to our MongoDB Atlas (both of which are hosted
on external servers on the internet)
- RESTful Routing
Level 1 Security
- The lowest level of security. Creating accounts for users, storing their email and password.
Level 2: Encryption
- Involves the use of encryption keys. Encoding and decoding, the other person cannot
understand the message unless you know how to decode that.
- With node, we can use a package called mongoose-encryption.
- It encrypts when you call .save() and it decrypts when you call .find().
- We store sensitive information in environment variables, such as API keys and such sensitive
information.
- We make use of node's module named dotenv.
- Using Environment variables to keep secrets safe.
- We use a file called .env, which is a hidden file and we will add our environment variables to
this file. Then to make use of these variables in node, access them via process.env.API_KEY
- And then add .env to your .gitignore file.
Level 3: Hashing
- Hashing takes away the requirement for having an 'encryption key'.
So how do you decrypt the secret without the key? Answer is that you don't.
- It's almost impossible to turn the hash back into its original password.
- So when a user registers, the hash of the password is generated, and this hash is stored.
Once the user logs in again, another hash is generated for the password they entered and these
2 hashes are compared. If they match, then it's correct.
Hence the password is never stored; only a hash is stored.
- In node, we use the package md5 for this.
Level 6: OAuth
- OAuth is an open standard for token based authorization.
- Third party login, by allowing users to login via google or facebook, and allowing these third
party websites to authenticate the users.
- Why is OAuth special?
1. Granular level of access.
The app developer can determine what kind of data they need from the user's facebook
account, and request those accordingly.
2. Read / Read + Write Access.
You can ask for read or both read and write access.
3. Revoke access.
The user can revoke access via these 3rd parties, like google or facebook.
- One user logs into the third party website (google or facebook), the third party sends them
either an 'authentication code', and an 'access token'. Via the access token, our app can
further ask for more pieces of information from the third party website.
-
REACT Js
- So, this line of code allows us to inject html code into our website like this:
ReactDOM.render(<h1> Hello checking? </h1>, document.getElementById("root"))
- React works by creating these jsx files, where we have html right in the body of a javascript
file. What happens behind the scenes here is that a compiler converts the html code to
javascript code. This is done by the module 'react'.
So inside the react module, there is something called Babel which is a javascript compiler.
- Babel is the javascript compiler used internally in React and it converts our javascript to very
simple javascript that is understood by all kinds of browsers.
Hence we can even use es6 and stuff with react, since it has all these modules internally
making sure it will work on every kind of browser.
- Hence we can use 'import' statements instead of require statements, which actually follow es6
format.
- ReactDOM can take only a single HTML element for the first argument. If we want to add
more, then it directly wont allow. Hence to get over it, we can wrap up all these html tags inside
a single <div> tag.
- Hence this is how we inject html code inside javascript code.
- The html tag we see in this syntax is neither a string nor HTML.
It is called JSX, and it is a syntax extension to JavaScript.
- Hence, JSX allows us to insert html inside of javascript files, and also allows us to insert
javascript inside that html itself.
- To add javascript code inside the html part of code in the js file, we write it within {} curly
braces. You can add any javascript expressions inside these curly braces. Although you cannot
add javascript statements like if and else loops.
Means that you can only add javascript that evaluates to a value inside the {} braces, and
cannot write statements like if else loops.
- Hence, with jsx, if you are writing js inside the html, you can write expressions but not
statements.
- Make sure that you write the attributes in camelCase in the jsx part.
- We make use of javascript properties in jsx, such as className in the html attributes instead
of class.
- Hence note that it is jsx, and not html even though it looks very similar to it.
- You can add the style attribute to jsx, and this style attribute takes a javascript object as its
argument. Although the recommended method for adding styles in react is by using the class
property of css itself.
- Components in react:
Since files can get really long, we split them up into components where each component has a
small part of the html file (rather jsx file).
- You can write a function which returns this html code, and then use that function's name as if it
were an html tag itself. Hence this way you can create custom html tags, each of which are
components.
- And by convention, name these functions with PascalCase.
- Make sure you write the self closing tags.
- And we can now move each of these functions for every component into separate jsx files and
then import them (since we have es6 with reactjs). Make sure you import React in all of these
jsx files.
- Hence the best practice is to move all the html (rather jsx) code out of this javascript file.
- This is the format we use to structure all Reactjs files, where we have the whole component
tree defined in the App.jsx file, which has all the custom components imported from other jsx
files which have each of those individual components.
- Import and export modules
There can be only one single default export per file. For importing the non-default ones, we use
the curly braces {}.
- For using react on vscode for our local development, we use npx which is a package runner
tool which comes with npm.
- 'npx create-react-app my-app' : Run this command on the terminal to create a new react
project.
This will install 'react' and 'react-dom' as we've seen previously, and will also install
'react-scripts' which allows us to run our react app locally and serve it up on our browser.
- Like we can have attributes associated with each html element, for example
<input id="firstName" class="userName" placeholder="Enter your name" value="Shi" />
Then you can obtain the element in the developer console tab and then access each of these
attributes of the html elements.
Similarly for the custom defined html tags, like <App/> or <Header/>, we can give it our custom
attributes, and these are called Props or properties.
It's almost like we are calling a function, and passing these values as props.
- So, inside our custom components (of html elements like <App/> and <Header/>), it sees each
of these as custom properties. So you cannot do the usual stuff like className, etc. These can
only be done on html's original tags and original elements like 'h1' or 'div', etc.
- The React Dev tools section shows us the React DOM Tree (like the chrome developer tools
showed us the HTML DOM tree).
In the React Dev Tools you can see each of the react components and their props as well.
- The chrome extension allows you to view the react component tree. You can view it like this in
the developer tools-
- Since we cannot use if else 'statements', we convert that logic into expressions where we do
conditional rendering. To do this, we make use of ternary operators and the && operator.
States in Reactjs
- We need the concept of states in reactjs in order to make the apps more interactive.
- The UI of your app is a function of the state of your app.
- So we make use of conditional rendering, and have the user interface being dependent on the
value of a state variable.
This kind of programming is called Declarative Programming. The other kind of programming is
called Imperative programming.
- Hooks allow us to hook into the state of our app and read or modify it.
One of the popular ones is called useState.
- One of the rules for using hooks is that you must use them inside a functional component.
- We use states for our website to update dynamically reflecting the updated state, without
having to refresh the webpage again.
- Handling events in React is very similar to handling events on DOM elements. The only
difference is that when writing events in React, they must be in camelCase.
- Best video series on React, very practical and easy to understand.
- You can update the state using this.setState(). An example of using this is when let's say you
do a handleClick event and on click you change the state, and set it to something else.
Note that you cannot use if and else 'statements' in place of this, since it's a rule in react that
you cannot have statements like this, instead only have expressions.
Hence this method is used to render something (some react component) only when the left
hand side condition is true.
- Another way of doing this is to use the ternary operator.
- useState()
TO BE CONTINUED!!