# Antra SEP
###### tags: `notes`
### nvm vs npm
nvm (Node Version Manager) is a tool that allows you to download and install Node.js.
npm (Node Package Manager) is a tool that allows you to install javascript packages.
---
## HTTP
### local storage vs cookie
cookie can be send to backend, localstorage only seen by user
difference: structure(key value pairs/string), cookie auto send data to backend
## HTML
### lang=en in html
![](https://i.imgur.com/tcRQ0Rs.png)
what's the difference btw Translation, Localization, and Internationalization?
* Internationalization(i18n): design for different locales
* Localization(L10N): translate into specific language
The name in rules
```
const foo = input[0] + (input.length-2) + input[input.length-1]
```
How does this work?
### href vs src
src: for source location
href: hyper link
### Why we put css link in head?
If we put it inside body and we have elements inside body, they might not be painted
=> also has performance issue if we put inside body
### node vs element
If we try to get element from body using script in head, will it work?
```
getElementByTagName('h1') //yes
querySelectorAll('h1') //no, nodeList is not dynamic
```
dom: text, element
getElementById: return Element
querySelectorAll: return NodeList
getElementByTagName: return a live html collection(element) => dynamic, will changed after some changes in DOM tree
### async & defer
* if use `async` in script, it'll wait for body scripts
* `async` attribute is only for external scripts (and should only be used if the src attribute is present)
### meta
The way to talk with the browser, is helpful for SEO, before rendering
![](https://i.imgur.com/8xyKnSt.png)
charset: how we encode our document
viewport: initial width
1 pixel is not 1 pixel: depends on different device, different resolution
KPI
### Traverse nodes
![](https://i.imgur.com/ebxK9KD.png)
Build a function inside our web api
```
for (let i = 0; i < node.childNodes.length; i++) {
get(node.childNodes[i])
}
```
### DOM (Document Object Model)
JS object that allow us to change the HTML. It's the `window.document` object on browser.
### semantic
http://web-accessibility.carnegiemuseums.org/resources/
#### provide non-semantic tag with semantic meating
using aria attribute
### SVG vs Canvas
Both are tag to draw something.
* SVG(Scalable Vector Graphics): help create scalable graphic which will not lose resolution even if it's bigger.
SVG icon ex. fontawesome
* Canvas: main purpose is just to draw.
We can use Canvas to draw the layout and inside the layout, use SVG graphics
## CSS
### CSS inline, block, inline-block
inline-block: can set height & width
inline: only takes the least space that element needs
### class naming rule
should follow rules to name the class
https://seesparkbox.com/foundry/bem_by_example
### css games
### css reset v.s. css normalize
* css reset
10 years ago, we have many browsers, each of them provide different default style, we have to reset the style so that it'll follow our rule.
Now, most of the browsers follow same standard styles, but not all of them, so we still need to reset css.
When we see `user agent stylesheet`, that means this style is provided by our browser.
![](https://i.imgur.com/Ug7kEOH.png)
```
*::before,
*::after,
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
```
The `*` includes everything except psuedo elements.
* css normalize
A library that helps us use the standard way to reset css.
https://meyerweb.com/eric/tools/css/reset/reset.css
### box-sizing
Give the ability to control the width and height.
`box-sizing: border-box` will include the border&padding into width calculating.
* content-box: width = content
This box will looks like 150px width because `content-box` make the width do not include the border.
```
.box {
width: 100px;
height: 100px
background-color: black;
border: 50px solid black;
box-sizing: content-box //default
}
```
* border-box: width = content+padding+border
This box will looks like 100px width.
```
.box {
width: 100px;
height: 100px
background-color: black;
border: 50px solid black;
box-sizing: border-box
}
```
Developers like boxer-box because we don't have to calculate tehe real width that'll appear on the screen. And it's why we want to reset css as `border-box`.
### Responsive Design
In css we use media query, in html use meta tag.
### mobile first
designing for mobile before designing for desktop
---
## JS
**topic: data type, var/let/const, class, IIFE**
### Primitive Data
* **Primitives**: string, number, boolean, undefined, symbol, null
A primitive is not an object(except null) and has no methods of its own. All primitives are *immutable*.
* **structural root primitive**: null
every object comes from null, null is primitive data because in the source code of ```typeof```, they didn't check for the null value
```
typeof(null) //object
```
![](https://i.imgur.com/Ee8D6vq.png)
### type coersion
automatic or implicit conversion of values from one data type to another (such as strings to numbers)
Ex. coerced the 9 from a number into a string
```
const value1 = '5'
const value2 = 9
let sum = value1 + value2
console.log(sum) //59
```
Ex. coerced the '911','abc' from a string into a number
```
typeof(+'911') //number
+'abc' //NaN
typeof(+'abc') //number
```
Ex. coerce boolean into number
```
console.log(true+false) //1
console.log(+true) //1
console.log(+false) //0
typeof(+true) //number
```
### == vs. ===
```
'911' == 911 //true
'911' === 911 //false
+'911' === 911 //true
```
### Object data
* Structural Types: object
ex. function, Function, Boolean, Symbol, Error, Number
Here are some of the standard objects. Notice some of these were on the primitive list too, but don’t confuse them. These act as **constructors** to create those types.
```
var a = Boolean('a')
console.log(a) //true
typeof(a) //boolean
```
* Methods of creating object
```
var obj = {}
//or
var obj2 = Object.create({})
```
* object cannot be compared
```
obj == obj2 //false
```
* object will hold the address
If we change data in an object, it'll just be changed
```
var obj = {
name: 'David'
}
function foo(input) {
input.name = 'Jojo'
console.log(input) // {name: 'Jojo'}
}
foo(obj)
console.log(obj) // {name: 'Jojo'}
```
---
### function keyword and var keyword
```
console.log(foo, foo2) //function, undefined
function foo() {}
var foo2 = function() {} //var foo2 will hoisting with undefined value, but not function
```
### var, let, const
scope: function, block
* Assign value to un-declared variable
```
a = 3
console.log(a) //3
```
* Get value before assigning value
var will have hoisting
```
console.log(a) //undefined
var a = 3
console.log(a) //3
```
* Get value before assigning/declaring value
```
console.log(a) //reference error
a = 3
console.log(a) //3
```
```
var a = 5
function foo(input) {
input = 6
console.log(input) //6
}
foo(a)
console.log(a) //5
```
**const** cannot be re-assigned, but object properties can, because the address of object is not changed
* const for object
```
const obj = {
name: 'David'
}
const obj2 = {
name: 'Coco'
}
obj = obj2 //error
obj.name = obj2.name //fine
```
* const for array
```
const arr = [1, 2, 3]
arr[0] = 100
console.log(arr) //[100, 2, 3]
```
We'll use const in declaring object, array, and some primitive data that'll not be changed
* function can hoisting, too!
```
console.log(foo()) //Dio
function foo() {
return 'Dio'
}
```
* But, if we use const and arrow function to declare a function, it'll not be hoisted
```
console.log(foo()) //Ref error
const foo = () => 'Dio'
```
* function will be overwrite
```
function foo() {
return 'Jojo'
}
console.log(foo()) //Dio!!!
function foo() {
return 'Dio'
}
```
| feature | var | let | const | function |
| -------- | -------- | -------- | -------- | -------- |
| hoisting | yes(fn scope) | no(block scope) | no(b) | yes(fn) |
| re-assign| yes | yes | no | yes |
---
#### Undefined v.s not defined(Reference Error)
Undefined: variable is declared but not defined
not defined: variable is not even declared
---
### Scope
Scope determines the accessibility (visibility) of variables.
```if, for, while``` are all block statements
* var will not be influenced by block scope
```
function foo() {
console.log(a) //undefined
if (1) { //from here
var a = 6
} //to here, is a block scope
console.log(a) //6
}
foo()
```
* let will be influenced by block scope
```
function foo() {
console.log(a) //not defined, ref error
if (1) {
let a = 6
}
console.log(a) //not defined, ref error
}
foo()
```
*
```
var a = 3
function foo() {
if (1) {
var a = 6
}
console.log(a) //6
}
foo()
console.log(a) //3
```
* If cannot find variable, it'll find from the parent scope
```
var a = 3
function foo() {
if (1) {
let a = 6
}
console.log(a) //3
}
foo()
```
*
```
var a = 3
function foo() {
console.log(a) //3
if (1) {
a = 6
}
console.log(a) //6
}
foo()
```
---
### Class (start from 47:35)
#### Create using syntax sugar in ES6 (js has no class)
```
class Person {
constructor(name) {
this.name = name
this.age = age
}
}
var david = new Person('David', 12)
console.log(david)
```
* getter/setter
get: ```class.getterMethod```, get class variable
set: ```class.setterMethod = newValue```, set new value to the class variable
```
class Person {
constructor(name, age) {
this._name = name
this._age = age
}
get name() {
return this._name
}
set name(newName) {
this._name = newName
}
}
const david = new Person('David', 12)
console.log(david)
>> { _age: 12, _name: "David" }
//getter
console.log(david.name)
>> 'David'
//setter
david.name = 'Coco'
console.log(david)
>> { _age: 12, _name: "Coco" }
```
* Add new methods to class
```
class Person {
constructor(name, age) {
this._name = name
this._age = age
}
get name() {
return this._name
}
set name(newName) {
this._name = newName
}
walk() {
console.log(`${this._name} is walking.`)
}
}
const david = new Person('David', 12)
david.walk()
>> David is walking.
```
---
#### Create using function
```
function Person(name, age) {
this.name = name
this.age = age
}
const david = new Person('David', 12)
console.log(david)
```
* Add new methods to class
1. in function (can be called by child)
2. use ```prototype``` on class (cannot be called by child)
3. use ```__proto__``` on any instance (accessible for all instances)
4. use ```class.method``` (only for the single instance)
```
function Person(name, age) {
this.name = name
this.age = age
//method 1:
thid.walk = function() {
console.log(`${this.name} is walking.`)
}
}
//method 2:
Person.prototype.walk = function () {
console.log(`${this.name} is walking.`)
}
```
#### ```__proto__``` v.s. ```prototype```
```__proto__``` is the property of **instance** object
```prototype``` is for the object itself
```
function Person(name, age) {
this.name = name
this.age = age
}
const p = new Person('David', 12)
console.log(p.__proto__ === Person.prototype) //true
```
We can also add method use ```__proto__```:
```
//method 3:
p.__proto__.walk = function() {
console.log(`${this.name} is walking.`)
}
p.walk()
>>> David is walking.
```
*Note this method will directly be added to the class!!!*
```
const p2 = new Person('Jojo', 12)
p2.walk()
>>> Jojo is walking.
```
If we just want to add a method on a single instance, we can simply do this:
```
//method 4:
p.walk = function() {
console.log(`${this.name} is walking.`)
}
```
---
#### OOP
There's no OOP concept in JS, but to mimic the OOP as in other languages, the class sugar syntax is introduced.
* **Encapsulation** (private data is protected)
Before ES2019, though we have getter/setter, people can still get/set data in class without getter/setter. Developers often using the underscore convention (```_data```) to indicate a private data.
In ES2019, private class fields are defined using a hash ```#``` prefix
1. private data must be declared ourside of constructor
2. can set default value to it
3. or use constructor to give it value
4. or simply use setter to set value
```
class Person {
//private data must be declared ourside of constructor!
#name
#age = 0
//this is not necessary
constructor(name, age) {
this.#name = name
this.#age = age
}
get name() {
return this.#name
}
set name(newName) {
this.#name = newName
}
get age() {
return this.#age
}
set age(newAge) {
this.#age = newAge
}
walk() {
console.log(`${this.#name} is walking.`)
}
}
const p = new Person('Coco', 22)
//can't get private data directly
console.log(p.#age)
>>> error
//use getter
p.age
>>> 22
//use setter
p.name = 'David'
```
https://www.sitepoint.com/javascript-private-class-fields/
* **Inheritance**
--- class way ---
1. ```super```: used to access and call functions on an object's parent
2. child class can access parent's methods
```
class Employee extends Person {
constructor(name, age, company) {
super(name, age)
this.company = company
}
}
const david = new Employee('David', 12, 'Antra')
david.walk()
>> David is walking.
```
--- function way ---
This will not inherit methods from parent.
```
function Employee(name, age, company) {
Person.call(this, name, age)
this.company = company
}
```
Inherite methods from parent:
```
Employee.prototype = Object.create(Person.prototype)
```
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance
* **polymorphism**
In general OOP: it'll include overloading & overriding
**overloading**: same method name, passing different number of parameters can use different methods
**overriding**: replace parent method with same method name
https://medium.com/@totoroLiu/%E7%89%A9%E4%BB%B6%E5%B0%8E%E5%90%91-object-oriented-programming-%E6%A6%82%E5%BF%B5-5f205d437fd6
But in JS, there's no overloading, only overriding
```
//parent
class Person {
constructor(name, age) {
this._name = name
this._age = age
}
get name() {
return this._name
}
set name(newName) {
this._name = newName
}
walk() {
console.log(`${this._name} is walking.`)
}
}
//child
class Employee extends Person {
constructor(name, age, company) {
super(name, age)
this.company = company
}
walk(num) {
console.log(`${this.name} walk for ${num} times`)
}
}
const david = new Employee('David', 12, 'Antra')
//parent method is overrided
david.walk()
>>> David walk for undefined times
```
Even if we define a new one in child, it won't be solved, because JS will use the last decalred function, if they're using the same name.
```
class Employee extends Person {
constructor(name, age, company) {
super(name, age)
this.company = company
}
walk() {
console.log(`${this._name} is walking.`)
}
walk(num) {
console.log(`${this.name} walk for ${num} times`)
}
}
const david = new Employee('David', 12, 'Antra')
david.walk()
>>> David walk for undefined times
```
* **abstract**
---
### IIFE
Why do need IIFE?
Create a function scope, so that it'll not influence the global object. Everything declared inside the IIFE will not effect global scope.
---
### modular pattern
---
### Loop through array
* for loop - for
```
const arr = [1, 2, 3]
for (let i = 0; i < arr.length; i++) {
console.log(arr[i])
}
```
* for loop - for of
```
const arr = [1, 2, 3]
for (let num of arr) {
console.log(num)
}
```
### forEach v.s map
* **forEach** will pass a callback function, execute the function once for each element of the array. Therefore, it cannot do return/break
syntax: ```arr.forEach( (currVal, idx, currArr) => {} )```
```
const arr1 = [1,2,3]
console.log(arr1.forEach(e => {
if (e === 2) {
console.log('return here')
return e
}
}))
//undefined
arr1.forEach(e => {
if (e === 2) {
break //not work
}
})
```
* **map** will create a new array according to return value, it cannot stop the loop, too
```
const arr = [1,2,3]
console.log(
arr.map(function (ele, index, currArr) {
console.log(ele, index, currArr)
if (ele !== 2) {
return 2
}
})
)
//[2, undefined, 2]
```
* map cannot directly change value with the current element parameter, we should change on ```currArr``` instead.
```
const arr = [1,2,3]
arr.map(function (ele, index, currArr) {
console.log(ele, index, currArr)
if (ele === 2) {
ele = 12
}
})
console.log(arr) //[1,2,3]
arr.map(function (ele, index, currArr) {
console.log(ele, index, currArr)
if (ele === 2) {
currArr[index] = 12
}
})
console.log(arr) //[1,12,3]
```
* **Build the forEach function**
syntax: ```myForEach( (currVal, idx, currArr) => {})```
return: none
```
Array.prototype.myForEach = function(callback) {
for (let i = 0; i < this.length; i++) {
callback(this[i], i, this)
}
}
```
Test:
```
const arr = [1, 2, 3]
const cb = function(currVal, idx, currArr) {
if (currVal === 2) {
currArr[idx] = 12
}
}
arr.myForEach(cb)
console.log(arr) //[1, 12, 3]
```
> [Answer the question]
> Q: Why forEach cannot return?
> A: Because there's no designed return
* **Build the map function**
syntax: ```myMap( (currVal, idx, currArr) => {})```
return: a new array after executing callback fn
```
Array.prototype.myForEach = function(callback) {
let newArr = []
for (let i = 0; i < this.length; i++) {
newArr.push(callback(this[i], i, this))
}
return newArr
}
```
Test:
```
const arr = [1, 2, 3]
const cb = function(currVal, idx, currArr) {
if (currVal === 2) {
return 2
}
}
arr.myMap(cb)
console.log(arr) //[undefined, 2, undefined]
```
---
### filter, find
* **filter**
Creates a new array with all elements that pass the test implemented by the provided function.
sytax: ```arr.filter( callback(currVal, idx, currArr), thisArg ) ```
thisArg(optional): value to use as **this** when executing callback
Ex.
```
function isInRange(value) {
if (typeof value !== 'number') {
return false;
}
return value >= this.lower && value <= this.upper; //here the "this" refers to the thisArg instance
}
let data = [10, 20, "30", 1, 5, 'JavaScript filter', undefined, 'example'];
let range = {
lower: 1,
upper: 10
};
let numberInRange = data.filter(isInRange, range);
console.log(numberInRange); // [10, 1, 5]
```
* **Build my filter**
```
Array.prototype.myFilter = function(callback) {
let newArr = []
for (let i = 0; i < this.length; i++) {
if ( callback(this[i], i, this) ) {
newArr.push(this[i])
}
}
return newArr
}
```
Test:
```
const arr = [1, 2, 3]
const cb = e => e===2
arr.myFilter(cb)
console.log(arr) //[2]
```
* **find**
Return the first elements that pass the test implemented by the provided function.
sytax: ```arr.find( callback(currVal, idx, currArr), thisArg ) ```
thisArg(optional): value to use as **this** when executing callback
* **Build my find**
```
Array.prototype.myFind = function(callback) {
for (let i = 0; i < this.length; i++) {
if ( callback(this[i], i, this) ) {
return this[i]
}
}
}
```
Test:
```
const arr = [1, 2, 3, 2]
const cb = e => e===2
arr.myFind(cb)
console.log(arr) //2
```
---
### some, every
---
### reduce
Executes a reducer function on each element of the array, resulting in single output value
sytax: ```arr.reduce( callback(acc, curr, idx, currArr ),initialAcc)```
initialAcc: initial value for accumulator
* **Build my reduce**
```
Array.prototype.myReduce = function(callback, initialAcc) {
let acc = initialAcc || 0
for (let i = 0; i < this.length; i++) {
acc = callback(acc, this[i], i, this)
}
return acc
}
```
Test:
```
const arr = [1, 2, 3]
const cb = (acc, curr) => acc+curr
console.log(arr.myReduce(cb)) //6
```
---
### Object forEach
```
const obj = { name: 'Dio', age: 200 }
for (let key in obj) {
console.log(obj[key])
}
//'Dio'
//200
```
---
### ES6 spread operator, rest parameters
* rest parameter
The rest parameter syntax allows a function to accept an indefinite number of arguments as an array.
Ex.
```
function foo(num, num2, ...args) {
console.log(args)
}
foo(1, 2, 3, 4) //[3,4]
```
* spread operator
Allows an iterable such as an array expression or string to be expanded.
Ex.
```
const foo = (input) => {
const set = new Set([...input])
return [...set].join('')
}
console.log(foo('qwerqwe')) //qwer
```
---
### shallow copy, deep copy
* **Shallow Copy**: addresses of X, Y is the same
* **Deep Copy**: copy of all the members of X, allocates different memory location for Y
There're 3 deep copy methods:
1. **spread operator**
```
const obj = {name: 'Dio'}
const obj2 = { ...obj }
```
2. **JSON**
```
const obj = {name: 'Dio'}
const obj2 = JSON.parse(JSON.stringify(obj))
```
3. Object.assign
syntax: ```Object.assign(target, ...sources)```
```
const obj = {name: 'Dio'}
const obj2 = Object.assign({}, obj)
```
---
### object? array?
The ```typeof``` array and object are both object, how to differentiate an array?
* array
```
let arr = []
// if there's Array keyword in object's constructor, it's array
arr.__proto__.constructor.toString().indexOf('Array') > -1
```
---
### Destructure(ES6)
* destructure array
```
const [a,b] = [1, 2]
console.log(a, b) //1,2
const [a, b] = [ {name: 'David'} , 2]
console.log(a) //{name: 'David'}
```
* destructure object
Note: getting value with wrong key name will cause error
```
const obj = {name: 'David', age: 20}
//wrong
const [name, age] = obj
//wrong
const {a, b} = obj
//correct
const {name, age} = obj
console.log(name, age) //David, 20
```
* rename object key
```
const {name: a, age} = obj
console.log(name, age) //result, 20
console.log(a, age) //David, 20
```
* React Hook
```
const arr = [
{ name: 'Dio' },
data => {
arr[0] = { ...arr[0], ...data }
},
]
const [state, setState] = arr
setState({ age: 200 })
console.log(arr[0]) //{ age: 200, name: 'Dio' }
console.log(state) //{ name: 'Dio' }
```
state data does not change because it's destructured before calling setState
---
### this
We have no idea what is `this` keyword until we know which part invoke this object.
Refers to the object that owns ```this```
* global
browser: Window[global]
IDE: Object [global]
* Object owns the method
```
const obj = {
foo() {
console.log(this)
}
}
obj.foo() //obj
```
* Newly created instance
```
class Person {
constructor(name) {
this.name = name
}
bar() {
console.log(this)
}
}
const p = new Person('Dio')
p.bar() //the object p
console.log(p) //the object p
```
---
### call, apply, bind
* **bind**
Create a new function and bind the method to an object
```
const obj = {
pi: 3.14,
getPi: function() {
return this.pi
}
}
function foo() {
console.log(`The value of pi is ${this.getPi()}`)
}
foo() //error: this.getPi is not a function
const bar = foo.bind(obj)
bar() //The value of pi is 3.14
```
* We can use parameters of the newly binded function
```
const obj = {
pi: 3.14,
getPi: function() {
return this.pi
}
}
function foo(circle, radius) {
console.log(`Area of circle ${circle} is ${this.getPi() * radius ** 2}`)
}
const bar = foo.bind(obj)
bar('Dio', 2) //"Area of circle Dio is 12.56"
```
* **call**
Bind the method to the first parameter(the object)
syntax: ```fn.call(obj, par1, par2, ...)```
```
foo.call(obj, 'Dio', 2) //"Area of circle Dio is 12.56"
```
* **apply**
syntax: ```fn.apply(obj, [par1, par2, ...])```
```
foo.apply(obj, ['Dio', 2]) //"Area of circle Dio is 12.56"
```
---
### Arrow function(ES6)
```=>``` will automatically bind ```this``` to the defining object. It’s no longer necessary to add bind declarations. 🎉
* A normal function inside a method without binding ```this``` refers to global object
```
const myObj = {
myMethod(item) {
console.log(this) //myObj
const foo = function() {
console.log(this) //global object
}
foo()
}
}
```
* With bind ```this```, it can refer to the object that owns this function
```
const myObj = {
myMethod(item) {
console.log(this) //myObj
const foo = function() {
console.log(this) //myObj
}.bind(this)
foo()
}
}
```
* Or, we can use arrow function to automatically bind ```this```
```
const myObj = {
myMethod(item) {
console.log(this) //myObj
const foo = () => {
console.log(this) //myObj
}
foo()
}
}
```
* arrow function cannot be used to create constructor function
Normal way to create a constructor: use function
```
const Car = function(color) {
this.color = color
}
const car = new Car('red')
console.log(car) //{color: 'red'}
```
Wrong way: use arrow function
```
const Car = (color) => {
this.color = color
}
const car = new Car('red')
console.log(car) //Car is not a constructor
```
* arguments of arrow function and normal function
```
function foo() {
console.log(arguments) //{0: "a", 1: "b"}
const bar = function() {
console.log(arguments) //{0: "c", 1: "d"}
}
bar('c', 'd')
}
foo('a', 'b')
```
```
function foo() {
console.log(arguments) //{0: "a", 1: "b"}
const bar = () => {
console.log(arguments) //{0: "a", 1: "b"}
}
bar('c', 'd')
}
foo('a', 'b')
```
---
### Closure
A closure gives you access to an outer function’s scope from an inner function
```
const foo = function() {
let a = 5
return function() {
console.log(a)
}
}
const bar = foo()
bar()
```
* After running the method, JS will not destroy variable inside it, so it'll not be reset
```
const limitedFunction = function(num, cb) {
let counter = 0
return function(...args) {
if (counter <= num) {
cb(...args)
counter++
}
else {
console.log('over limit')
}
}
}
const fn = limitedFunction(3, (a, b) => console.log(a + b))
fn(2, 3) //5
fn(2, 3) //5
fn(2, 3) //5
fn(2, 3) //over limit
```
* code challenge
Q: create a function foo
```
console.log(foo(4, 23, 2)(2)(12,1))
```
A:
```
const foo = (...args1) => (...args2) => (...args3) => {
return [...args1,...args2, ...args3].reduce( (acc, curr) => acc+curr)
}
```
---
### Async, Event Loop
Mechenism for JS to handle the async task.
**contains 3 parts**: call stack, async API, message queue(task)
async statement: ```setTimeout```, ```ajax```, ```promise```, ```click``` event
**Main Stack**: where all javascript code gets pushed and executed one by one
**Callback Queue**: where asynchronous code gets pushed to, and waits for the execution.
**Job Queue**: Apart from Callback Queue, reserved only for ```new Promise()``` functionality. Has higher priority than callback queue.
**Event Loop**:
keeps running
1. checks Main Stack, and run frames inside it until empty
2. checks Callback Queue, pops messages from it to the Main Stack for the execution
Ex.
* step 1: push to call stack
```
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), i*1000 )
}
//call stack: foo, i
//async API: console.log(i), console.log(i), console.log(i), console.log(i), console.log(i)
//message queue:
```
* step 2: push to async api
```
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), i*1000 )
}
//call stack: foo, i
//async API: console.log(i), console.log(i), console.log(i), console.log(i), console.log(i)
//message queue:
```
* step 3: push from async api to message queue
```
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), i*1000 )
}
//call stack: foo, i
//async API:
//message queue: console.log(i), console.log(i), console.log(i), console.log(i), console.log(i)
```
* result
```
5
5
5
5
5
```
* Modify 1
Create a new scope and put the console.log variable inside it.
In this case, ```num``` will be different each time we call the function
```
for (var i = 0; i < 5; i++) {
(function(){
var num = i
setTimeout(() => console.log(num), num*1000 )
})()
}
```
* async api doesn't have to be pushed into message queue in order, it's depends on time
```
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), (5-i)*1000 )
}
//async API: console.log(0) with 5s, console.log(1), console.log(2), console.log(3), console.log(4) with 1s
//message queue: console.log(4), console.log(3), console.log(2), console.log(1), console.log(0)
//4
//3
//2
//1
//0
```
### callback hell
```
const foo = () => {
console.log('foo')
}
const getRandomTime = () => {
return Math.floor(Math.random()*6)
}
const callFnInRandomTime = (cb) => {
const timer = getRandomTime()
console.log(`wait for ${timer}s to call a function`)
setTimeout(cb, timer*1000)
}
//to call a function after calling a function...
//callback hell
callFnInRandomTime(() => {
callFnInRandomTime(() => {
callFnInRandomTime(() => {
callFnInRandomTime(foo)
})
})
})
"wait for 3s to call a function"
"wait for 2s to call a function"
"wait for 2s to call a function"
"wait for 2s to call a function"
"foo"
```
### XHR(XMLHttpRequest)
```
function getUser(cb, id) {
let xhttp = new XMLHttpRequest()
xhttp.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200) {
const data = JSON.parse(xhttp.response)
cb(data)
}
}
const url = 'https://jsonplaceholder.typicode.com/posts/'
xhttp.open('GET', url + id, true)
xhttp.send()
}
function print(data) {
console.log(data)
}
getUser(print, 5) //get data with id=5
```
* If we want data in the order 5, 12, 3...
Approach 1: callback
```
getUser(data => {
print(data)
getUser(data => {
print(data)
getUser(data => {
print(data)
}, 3)
}, 12)
}, 5)
```
### Promise
promise is async
* usage: resolve
```
const getRandomTime = () => {
return Math.floor(Math.random() * 6);
}
const p = new Promise((resolve, reject) => {
const timer = getRandomTime();
console.log(`${timer}s`);
setTimeout(() => {
resolve('hello');
}, timer * 1000);
})
.then(data => {
console.log('this is first data: ', data);
return data + 2;
})
.then(data => console.log('this is second data: ', data))
//"wait for 4s"
//"This is first data hello"
//"This is second data hello2"
```
```then``` will receive the data from resolve and call a callback function, and the return will transfer data to the next ```then```
* usage: reject
```
const p = new Promise( (resolve, reject) => {
const timer = getRandomTime()
console.log(`wait for ${timer}s`)
if (timer > 3) {
reject({timer: timer, message: 'fail'})
}
setTimeout(() => {
resolve('hello')
}, timer*1000 )
})
.then( data => {
console.log(`This is first data ${data}`)
return data+2
})
.then( data => {
console.log(`This is second data ${data}`)
})
.catch(err => console.log(err))
//"wait for 4s"
//{ message: "fail", timer: 4 }
```
* replace callback hell
In this way, we can print users in our wish order
```
const getUser = id => {
return new Promise( (resolve, reject) => {
const xhttp = new XMLHttpRequest()
const url = 'https://jsonplaceholder.typicode.com/posts/'
xhttp.open('GET', url + id, true)
xhttp.send()
xhttp.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200) {
const data = JSON.parse(xhttp.response)
resolve(data)
}
}
})
}
getUser(5)
.then( data => {
console.log(data)
return getUser(12)
})
.then( data => {
console.log(data)
return getUser(3)
})
.then( data => {
console.log(data)
})
```
### async/await v.s. Promise
They are the same, async/await is just syntax sugar of promise. It enables asynchronous, **promise-based** behavior to be written in a cleaner style.
```
const getUser = id => {
return new Promise( (resolve, reject) => {
const xhttp = new XMLHttpRequest()
const url = 'https://jsonplaceholder.typicode.com/posts/'
xhttp.open('GET', url + id, true)
xhttp.send()
xhttp.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200) {
const data = JSON.parse(xhttp.response)
resolve(data)
}
}
})
}
const getUsers = async () => {
const data5 = await getUser(5)
console.log(data5)
const data12 = await getUser(12)
console.log(data12)
const data3 = await getUser(3)
console.log(data3)
}
getUsers()
```
* catch error
```
const getUser = id => {
return new Promise( (resolve, reject) => {
const xhttp = new XMLHttpRequest()
const url = 'https://jsonplaceholder.typicode.com/posts/'
xhttp.open('GET', url + id, true)
xhttp.send()
xhttp.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200) {
const data = JSON.parse(xhttp.response)
reject({message: 'fail'})
}
}
})
}
const getUsers = async () => {
try {
const data5 = await getUser(5)
console.log(data5)
const data12 = await getUser(12)
console.log(data12)
const data3 = await getUser(3)
console.log(data3)
} catch (error) {
console.log(error)
}
}
//{ message: "fail" }
```
### Construct Promise
Since Promise use the ```new``` keyword, we can construct it using class
* resolve
```
class MyPromise {
thenCallBackQueue = [];
constructor(exe) {
exe(this.resolve, this.reject);
}
resolve = (data) => {
const cb = this.thenCallBackQueue.shift();
cb(data);
}
reject() {}
then(thenCallBack) {
this.thenCallBackQueue.push(thenCallBack);
}
catch(catchCallBack) {}
}
const p = new MyPromise((resolve, reject) => {
setTimeout(() => resolve('hello'), 0);
})
.then(data => { //
console.log('this is data: ', data);
})
```
```
class MyPromise {
thenCallBackQueue = [];
currentData;
constructor(exe) {
exe(this.resolve, this.reject.bind(this));
}
resolve = (data) => {
setTimeout(() => {
this.currentData = data
while (this.thenCallBackQueue.length) {
const cb = this.thenCallBackQueue.shift() //get the first element
if (this.currentData instanceof MyPromise) {
this.currentData.then((d) => {
this.currentData = cb(d)
})
} else {
this.currentData = cb(this.currentData)
}
}
}, 0)
}
reject() { }
then(thenCallBack) {
this.thenCallBackQueue.push(thenCallBack);
return this;
}
catch(catchCallBack) { }
all() {}
}
const p = new MyPromise((resolve, reject) => {
// setTimeout(() => resolve('hello'), 0);
resolve('hello');
})
.then(data => { //
console.log('this is data: ', data);
return new MyPromise((res, rej) => {
// setTimeout(() => {
res('Dio')
// }, 0);
});
})
.then(data2 => console.log('this is data2: ', data2))
// .catch(err => console.log(err));
```
* Note: use arrow function to avoid from using bind
* **Promise State**
If we console.log Promise on browser, there will be:
```
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined
```
There're 3 states of Promise:
1. pending: initial state, neither fulfilled nor rejected.
2. fulfilled: meaning that the operation was completed successfully.
3. rejected: meaning that the operation failed.
![](https://i.imgur.com/cK7iTFW.png)
* **Promise all**
syntax:
```Promise.all``` will return a new Promise object
```
const p1 = fetch('https://jsonplaceholder.typicode.com/todos/1').then((d) =>
d.json()
)
const p2 = fetch('https://jsonplaceholder.typicode.com/todos/2').then((d) =>
d.json()
)
const p3 = fetch('https://jsonplaceholder.typicode.com/todos/3').then((d) =>
d.json()
)
Promise.all([p1, p2, p3]).then((v) => {
console.log(v)
})
```
* build
```
static all(arr) {
let counter = 0
const resolveData = []
return new MyPromise((res, rej) => {
arr.forEach((el, i) => {
el.then((data) => {
counter++
resolveData[i] = data
if (counter === arr.length) res(resolveData)
})
})
})
}
```
*Note: The ```static``` keyword defines a static method or property for a class. It cannot be called on instances.*
### Array methods
* push
* shift
* pop
* unshift
difference: performance
if dequeue a lot: use pop+unshift
if enqueue a lot: use shift+push
### Fetch
structure: ```fetch(url, object)```
return: a Promise
```
function myFetch(url, options) {
return new Promise((res, rej) => {
var xhttp = new XMLHttpRequest()
xhttp.open(options.method, url, true)
if (options.headers) {
for (let key in options.headers) {
xhttp.setRequestHeader(key, options.headers[key])
}
}
xhttp.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status >= 200 && this.status < 300) {
const response = {
json: () => JSON.parse(xhttp.response),
}
res(response)
} else {
rej({ readyState: this.readyState, errorStatus: this.status })
}
}
}
xhttp.send(options.body)
})
}
//usage
myFetch('https://jsonplaceholder.typicode.com/postsasdas', {
method: 'POST',
body: JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1,
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
})
.then((response) => response.json())
.then((json) => console.log(json))
```
---
## React
1. just an ui-library
2. one way data binding
### library v.s. framework
**What is library?**
Just help you to solve a certain problem, React only handle the view part, can develop with many different libraries with developers' own rule
**Example**
React, JQuery, lodash, underscore, three.js, etc
**What is framework?**
Will contain several libraries, providing a standard rule to do everything, developers have to follow the rules
**Example**
Vue, Angular, Express, koa2
> ### Since React is just a view library, we still need other tools to do development.
---
### Ways of creating React project
1. **boilerplate**: `npx create-react-app`
2. **CDN**(content delivery network): put at the end of body
Online resources providers that can send you static resources based on your location. Can also help your website optimize the website performance.
> ### How to create a React project with CDN, instead of boilerplate?
Importing `React` & `ReactDOM` as global object
```
<body>
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
</body>
```
### React v.s. ReactDOM
* **React**: generates virtual DOM, including methods like `createElement`, which is used when tranforming JSX to JS
* **ReactDOM**: An api, helps you touching the real DOM, by comparing the virtual DOM with real DOM, and updating real DOM
There're many methods of ReactDOM, including render
### Virtual DOM v.s. (HTML)DOM
```
<button class="add">Add</button>
<ul class="list"></ul>
<script>
const btn = document.querySelector('.add')
const ul = document.querySelector('.list')
const list = ['Patric', 'Sam', 'Jane']
btn.addEventListener('click', () => {
list.push('newName')
ul.innerHTML = list.map((name) => `<li>${name}</li>`).join('')
})
ul.innerHTML = list.map((name) => `<li>${name}</li>`).join('')
</script>
```
**Issues of html DOM**
Follows the MVC pattern, once data change, the ui change.
Therefore, in this example, everytime we add a new item to the list, it'll re-generate all `li`.
It's hard for traditional DOM to find the best way to update your DOM, which is, only create the new `li` element
**Why virtual DOM?**
React uses the `diff` algorithm to compare the previous virtual DOM with next virtual DOM, find the best way to update it
**More Info**
https://reactkungfu.com/2015/10/the-difference-between-virtual-dom-and-dom/
---
### JSX -> pure JS
❌ JSX cannot be understood by JS
```
class HelloMessage extends React.Component {
render() {
return <div>Hello {this.props.name}</div> //error here
}
}
ReactDOM.render(
<HelloMessage name="Taylor" />,
document.getElementById('hello')
)
```
✨ JSX: A syntax sugar, looks like JS+HTML, need compiler(ex. babel) to transpile it into JS, let the browser understand it.
✨ Babel can help us transpile JSX to JS with the function `createElement`
⛏ Replace the JSX with `createElement` method in `React` object
```
//before
<div>Hello {this.props.name}</div>
//after
React.createElement('div', null, 'Hello ', this.props.name)
```
```
//before
<HelloMessage name="Taylor" />
//after
React.createElement(HelloMessage, {
name: 'Taylor',
})
```
https://zh-hant.reactjs.org/docs/introducing-jsx.html
---
### web component
self-definition tag
Nothing to do with React
https://developer.mozilla.org/en-US/docs/Web/Web_Components
---
### npm
#### `package.json`
```
{
"name": "notes",
"version": "1.0.0",
"description": "",
"main": "index.js", //entry point of the project
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
```
#### npm script
* For default scripts, `npm run <script>` & `npm <script>` both works.
* For custom scripts, we have to follow the original command `npm run <script>`
#### install packages
`npm install --save-dev @babel/core @babel/cli`
The `--save-dev` means it'll install packages as `devDependencies`, which will not be installed in production.
#### `^7.12.13`
The `^` i means above which version
#### `package-lock.json`
* Why this file?
Generally, we might not install the same version simply with the same command `npm install --save-dev @babel/core @babel/cli` for now and one year later.
* Solution
To help developers use the same package versions in a project, with `package-lock.json`, we can install the same versions just run `npm install`
---
❓ It's troublesome to write pure JS for React everytime, is there a way to transform JSX to JS for us?
❗ Here comes the Babel
---
### Setup the Babel: transpile JSX to JS
Follows the steps on https://babeljs.io/setup#installation
1⃣ **Install Babel cli**
```
npm install --save-dev @babel/core @babel/cli
```
2⃣ **Set npm scripts**: instead of running babel directly(babel is not a script in cli)
- Issue
When we run the script `"build": "babel src -d lib"`
It shows the error:
```
Add @babel/preset-react (https://git.io/JfeDR) to the 'presets' section of your Babel config to enable transformation.
```
- Solution: add preset
**What is presets?**
Let Babel know what kind of JS code Babel is going to transpile. Ex. preset for react, preset for ES6, etc.
3⃣ **Set preset:**
1. Run npm install --save-dev @babel/preset-react
2. Create a babel.config.json file
3. Add the following into json file
```
{
"presets": ["@babel/preset-react"]
}
```
After build, we can see the transformed js in lib folder.
---
### Structure(after using babel)
- `src` folder
The `npm run build` will transpile contents in `src` to `lib` folder
- `lib` folder
Contains files that's generated by Babel
- `public` folder
1. include`index.html`
2. put CDN inside this file
3. set the `id=root` div
4. import `index.js` from `lib`
```
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script
crossorigin
src="https://unpkg.com/react@17/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"
></script>
<script src="../lib/index.js"></script>
</body>
</html>
```
Here's an error `Uncaught SyntaxError: Cannot use import statement outside a module` related to `import Home from './components/Home'`
**This is because `import` is a method in node.js not browser.**
There's actually the `import` syntax in ES6, but not widely used https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/import
---
### NodeJS vs JS vs EcamScript
* EcamScript: syntax standard(ex. ES6)
* JS: EcamScript + Web API(ex. DOM)
in browser:
```
console.log(this)
>>> Window {window: Window, self: Window, document: document, name: "", location: Location, …}
//these are web apis
```
* NodeJS: EcamScript + Node API
in terminal:
```
console.log(this)
>>> Object [global] {...}
```
> ### The problem of cannot using node method in browser, is called bundling, and we can solve it with webpack.
**What is bundling?**
Bundling merges multiple JavaScript files together into one file.
https://medium.com/@gimenete/how-javascript-bundlers-work-1fc0d0caf2da
And webpack can do more than bundling.
---
### Standards of using JS Modules
This standard has been adopted by NodeJS, so it's widely seen in NodeJS projects. However, it's not supported by the browser.
That's why we need webpack or Browserify.
* CommonJS
| Use`require` and `module.exports`
two ways of exporting: **named** and **default exports**
```
//default export
const a = 5
module.exports = a
//named export
module.exports.a = 5
```
two ways of importing
```
// named import without changing the name a
const { a } = require('...')
// named import changing the name into b
const { a: b } = require('...')
// Default import
const a = require('...')
```
* ES Modules(ESM)
| Use `import` and `export`
two ways of exporting: **named** and **default exports**
```
//default export
export const a = 5
//named export
export default a
```
two ways of importing
```
// named import without changing the name a
const { a } = require('...')
// named import changing the name into b
const { a: b } = require('...')
// Default import
const a = require('...')
```
CommonJS is the native module system for NodeJS, but ESM is not. If we try to use ESM, it'll show error like this:
```
SyntaxError: Cannot use import statement outside a module
```
To use ESM, there're few solutions:
1. Change the file extension from `.js` to `.mjs`
2. Set `"type": "module"` in package.json ???
https://auth0.com/blog/javascript-module-systems-showdown/
https://medium.com/computed-comparisons/commonjs-vs-amd-vs-requirejs-vs-es6-modules-2e814b114a0b
https://blog.huli.tw/2020/01/21/webpack-newbie-tutorial/
https://dev.to/exacs/node-js-12-supports-es-modules-do-you-know-the-difference-between-commonjs-and-es2015-modules-hg9
---
### Setup the Webpack: in order to use NodeJS module
Ex. minify, uglify, polyfill
**1. create config file**
Under your project folder, create a file `webpack.config.js` with the content copy from https://webpack.js.org/
```
const path = require('path') //what is the path here?
module.exports = {
entry: './lib/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
}
```
* The path in line 1 helps us generate the path, which is natively supported by NodeJS, but cannot be used in the browser
* **Which `index.js` file should be the entry point?**
The order should be : babel -> bundle!!
Therefore, we should use the after babling file `lib/index.js` as entry point, not `src/index.js`
* The output content will be put at `dist/bundle.js`
**2. install webpack cli**
```
npm install webpack webpack-cli --save-dev
```
So that we can run `webpack ...` in shell
**3. Set webpack cli in `package.json`**
```
"build-webpack": "webpack --config webpack.config.js"
```
> ### Now finally see the result! But, what if we want to remove the CDN in the `index.html`?
---
### import React&ReactDOM instead of CDN
First, we have to install react&react-dom modules with node
```
npm i react react-dom
```
Second, we have to import React & ReactDOM to corresponding files
**For the root file `index.js`:**
```
import Home from './components/Home'
import ReactDOM from 'react-dom'
import React from 'react'
ReactDOM.render(<Home name="Taylor" />,
document.getElementById('root'))
```
Clearly, we need `ReactDOM` here. We also need `React` because the `<Home>` tag has to be tranformed to `React.createElement(Home, {
name: "Taylor"
})`
**For child component `Home.js`:**
```
import React from 'react'
class Home extends React.Component {
render() {
return <div>Home {this.props.name}</div>
}
}
export default Home
```
---
### Structure(after using webpack)
We use webpack to solve the issue of cannot use `import Home` in JS, and install `react`&`react-dom` libraries so that we don't have to use CDN
- `src` folder: `npm run build-babel` will transpile contents in `src` to `lib` folder
- `lib` folder: contains files that's generated by Babel
- `dist` folder: contains `bundle.js` after execute `npm run build-webpack`
- `public` folder
1. remove the CDN inside this file
2. instead of importing `lib/index.js`, importing `dist/bundle.js`
---
### webpack loader
* SASS/SCSS
We can use loader in webpack to tranpile everything including SASS to CSS.
* Babel
With webpack loader, we don't need to setup babel anymore, we can just install babel-loader
---
> ### This is why React is just a library, React only provide React&ReactDOM object, we still need like webpack to start a React project.
---
### AJAX | SPA | JSON
* AJAX
**What is AJAX?**
Allows websites change the DOM **without refreshing the page**, only data transferring.
**Benefit of AJAX**
Makes SPA websites possible.
**Where can we see it?**
In the browser developer's inspect, the network section, we can see the *XHR(XMLHttpRequest)*, when we use AJAX techniques to send data, it'll show some data transfer there.
* SPA
**What is SPA?**
Single Page Application. Enables the application to have only one html file, and looks like changing pages using only JS.
**Why do we need SPA?**
A SPA website doesn't have to refresh(get the whole page from server) everytime we change the url, which reduces the delay.
**Example**
MPA(Multi Page Application): https://about.google/
SPA(Single Page Application): https://reactjs.org/docs/getting-started.html
* JSON
**What is JSON?**
A key-valued data type, full name is JavaScript Object Notation.
**Why do we prefer to use JSON to transfer data, instead of using XML?**
1. light
2. natively supported by JS
We can use `JSON.parse` to transform data
---
### `.jsx` v.s. `.js`?
When React just released, it's recommended to use `.jsx` file to indicates that in this file, it's using JSX syntax, and so when the babel transpiling files, it'll know `.jsx` file needs JSX transform and `.js` file doesn't.
But as it getting more mature, we don't have to use the doc name to distinguish them, the babel will read the file and when it sees JSX syntax, it'll know it's a JSX file.
---
### CRA(Create React App)
We've introduced how to use CDN, babel, webpack to setup a react project. An easier way is to use the one-line-command `npx create-react-app my-app`.
#### What is `npx` ?
`npx` is a package runner, different from `npm` which only helps you installing packages.
`npx create-react-app` will firstly install the `create-react-app` and then remove it. Therefore, `create-react-app` is not a global command, and we only need to run it once.
After the react project created, we can see the structure like this:
- `public` folder: contains `index.html`, `favicon.ico`, `manifest.json`, `robots.txt` etc.
#### manifest.json
A summary of the web app
#### robots.txt
Define how we dealing with robots on the internet(ex. web crawler), like defining which files cannot be accessed...
#### `react-scripts`
After we run `npm start`, it'll run the command start script defined inside `package.json`
```
//package.json
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
```
As we knew, a react project should use babel, and it's included inside `react-scripts`.
If we open the `react-scripts` folder in node_mosuldes folder, inside the `package.json` file, we can see babel is a dependency of this module.
```
"dependencies": {
"@babel/core": "7.12.3",
```
> #### The react-scripts module automatically includes many dependencies for us, but what if we want to customize our own dependencies?
#### `eject`
We can use the `eject` script defined in the package.json.
After running `npm run eject`:
1. new folders `config` and `scripts` are generated
2. cannot go back to original react project generated by the CRA
3. we can still run `npm start` to start the react project, but the actual command is different, it's using `node` rather than `react-scripts` as before
```
//package.json after ejected
"scripts": {
"start": "node scripts/start.js",
"build": "node scripts/build.js",
"test": "node scripts/test.js"
},
```
---
### Structure your project
There're two common ways:
**1. By Function**
- components
- - Counter
- - - Counter.js
- apis
- models
- utils
some reusable helper methods, ex. string manipulation
- styles
every css or scss files here should be globally, specific component style should be put inside each component folder
**2. By Feature**
- ToDo
- - put every component, api, ..., related to ToDo feature inside this folder
- Counter
---
### Atomic design
Make components more reusable
---
### export ways
1. export default
```
export default
import Template from './components/templates'
```
2. named export
```
export { Template, AnotherTemplate }
import {Template, AnotherTemplate} from './components/templates'
```
---
### Fragment
Since JSX element must have root node, we can use `React.Fragment` as a root node. The benefit of using Fragment instead of `div` is, when we designing the css, there'll not have an unexpected node.
```
<React.Fragment>
<div></div>
<button></button>
</React.Fragment>
```
Or using the new syntax sugar `<></>`:
```
<>
<div></div>
<button></button>
</>
```
---
### Lifecycle
https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
![](https://i.imgur.com/XakHj6a.png)
1. Mounting
**What does this phase do?**
To initialize the react structure, the virtual DOM, previous DOM
**Process**
constructor -> getDerivedStateFromProps -> render -> componentDidMount
**Where can we get element?**
If not yet exists, get `null`
constructor(`null`) -> getDerivedStateFromProps(`null`) -> render(`null`) -> componentDidMount(not `null`)
**render**
the render method is helping us to generate the new virtualDOM
**componentDidMount**
Once the component has been mounted, this method will be triggered, and we can touch the real DOM
Usually we'll put data manipulation like `fetch`. Because after this method, the react is ready for updating
2. Updating
**What does this phase do?**
If we want to change the UI using the state
**How to trigger the update?**
* new props
If we pass data using `props`, when the `props` changes, the component will update
* setState
If we call `setState` in the component
* forceUpdate
React is using prototype chain, and `forceUpdate` is a method of class components' parent. Therefore, to call this method, we just need to call `this.forceUpdate`
![](https://i.imgur.com/9KuHPGk.png)
**Process**
getDerivedStateFromProps -> shouldComponentUpdate -> componentDidUpdate
* getDerivedStateFromProps
Tansform props that passing into this component into state
#### React will use recursion to generate the virtual DOM. So, the most child will be triggered to the end in the parent render method, and then parent goes to the end.
Suppose `Layout` is a child of `App`
```
//App component
render() {
console.log('App - render')
return (
<Layout content="Page1|Page2">
<Counter></Counter>
</Layout>
)
}
```
The process of lifecycle would be like this:
```
App - construct
App - getDerivedStateFromProps
App - render
Layout - construct
Layout - getDerivedStateFromProps
Layout - render
Layout - componentDidMount
App - componentDidMount
```
* shouldComponentUpdate
When the parent compnent update, it'll trigger the update of child component, but it's redundant and reduce the performance.
Without `shouldComponentUpdate`, the process will be:
```
update
App - getDerivedStateFromProps
App - render
Layout - getDerivedStateFromProps
Layout - render
```
After we defined the `shouldComponentUpdate` method:
```
update
App - getDerivedStateFromProps
App - render
Layout - getDerivedStateFromProps
Layout - shouldComponentUpdate
```
If we go to the source code of `shouldComponentUpdate`, we can see there're few parameters: `nextProps`, `nextState`, `nextContext`
```
shouldComponentUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): boolean;
```
Let's try to compare the values of currentProps/nextProps and currentState/nextState
```
shouldComponentUpdate(nextProps, nextState) {
console.log(nextProps === this.props) //false
console.log(nextState === this.state) //true
}
```
Since we haven't defined the state, it's `null`.
And since we're passing props, it's an object, but object is not comparable, so the equality will always be false. We can compare the property of props.
The return boolean value will determine whether the component should be updated.
- `true`: update -> render again
- `false`: do not update -> do not render
Therefore, we can set only if the current value inside the props is different from previous props value, do we update this component.
```
//Layout component
shouldComponentUpdate(nextProps, nextState) {
return nextProps.content !== this.props.content
}
```
---
#### Component vs PureComponent
They're basically the same. But, `PureComponent` will automatically generate the `shouldComponentUpdate`, and do the shallow(react use shallow copy) comparison between nextProps/this.props and nextState/this.state.
---
* componentDidUpdate
If the component did update, it'll end with this method
3. Unmounting
**Why do we need this phase?**
If we don't do unmounting, it'll cause memory leak, that means, any JS objects, functions inside this component will not be clean up, and functions like `setInterval` will continue to run.
```
//App
//Initialize a state: test
this.state = {
test: null,
}
render() {
console.log('App - render')
return (
<Layout content="Page1|Page2">
<button onClick={() => { this.setState({test: 'test'}) }}>
Update
</button>
//the Counter comopnent will be unmounted after we click the update button
{!this.state.test ? <Counter></Counter> : null}
</Layout>
)
}
//Counter
componentWillUnmount() {
console.log('Counter - unmounting')
}
```
**Notice**: if we keep the return value of `shouldComponentUpdate` inside the parent component of `Counter` as `false`, the `Counter` component will not be updated.
If we clicked the update button, we can see that `Counter - unmounting` shows up after the `Layout - render`.
*What if we don't do anything inside the `componentWillUnmount` when there's some functions like `setInterval`?*
```
//Counter
componentDidMount() {
setInterval(() => {
this.setState({
counter: this.state.counter + 1,
})
console.log('interval triggered')
}, 1000)
}
```
Even the `Counter` component is unmounted, the `console.log('interval triggered')` is kept triggerring. To solve this issue, after we unmount the component(in the `componentWillUnmount`), we have to call `clearInterval`.
```
//Counter
componentDidMount() {
this._intervalID = setInterval(() => {
this.setState({
counter: this.state.counter + 1,
})
console.log('interval triggered')
}, 1000)
}
componentWillUnmount() {
clearInterval(this._intervalID)
}
```
---
### data binding
React can do both one-way data binding and two-way data binding, but it's using **one-way data flow**.
```
<>
<h1>Counter: {this.state.counter}</h1>
<button onClick={this.handleAdd}>Add</button>
</>
```
This click event implementing a two-way data binding. From view to model(click button, change state), and model to view(according to state, change counter value on the screen)
https://tkssharma.gitbook.io/react-training/day-01/react-js-3-principles/one-way-data-flow
In React JS, data flows in one direction, from **Parent to Child**
#### props - parent to child
1. We can define props name on the component
```
//in the parent component
<Layout content='Page1'></Layout>
//in the Layout component
this.props.content //Page1
```
2. Anything between the child component tag is also props called `props.children`
```
//in the parent component
<Layout content='Page1'>Hello</Layout>
//in the child component
this.props.children //Hello
```
#### How to pass from child to parent?
We can lift up the states and using some state management tool like `Redux`, `ContextAPI`
* Redux: help us create global state which can be shared between components
#### view to model
Using event bind
```
handleUserInputChange = (e) => {
this.setState({
userInput: e.target.value,
})
}
```
#### model to view
Using state and value
```
<input
className="todolist-inputbar"
placeholder="What are you going to do?"
value={this.state.userInput}
onChange={this.handleUserInputChange}
></input>
```
*This achieved two-way data binding.*
---
### Class Component
**state**
We can directly define state inside the class (it's supported by the JS method `_defineProperty`).
```
class Counter extends Component {
state = {
counter: 0
}
render() {
return <h1>Counter: {this.state.counter}</h1>
}
}
```
But, usaually, we use constructor inside class component to define the state
```
class Counter extends Component {
constructor(props) {
super(props)
this.state = {
counter: 0,
}
}
render() {
return <h1>Counter: {this.state.counter}</h1>
}
}
```
#### super(props)
We use `super(props)` to invoke the parent constructor `React.Component`, so that the child component can use all the properties of the parent constructor.
---
**`this.setState` is an async method**
If we run `this.setState` twice, trying to adding 2 onto the counter...
```
//react method
handleAdd() {
this.setState({
counter: this.state.counter + 1, //this.state.counter is 0 here
})
this.setState({
counter: this.state.counter + 1, //this.state.counter is still 0 here
})
}
```
It'll still add only 1 onto it.
Let's mimic an async setState method:
```
//pure JS
let component = {
state: {
counter: 0
}
}
function setState(newState) {
setTimeout(()=>{
component.state = newState
}, 0)
}
setState({ counter: component.state.counter + 1 })
//component.state.counter here is 0
console.log(component.state.counter)
>>> 0
setState({ counter: component.state.counter + 1 })
//component.state.counter here is 0
console.log(component.state.counter)
>>> 0
```
**How to solve this issue?**
Since `setState`is async, we can pass a *callback function* into it.
```
//react method
handleAdd() {
this.setState((preState) => {
return {
counter: preState.counter + 1, //this.state.counter is 0 here
}
})
this.setState((preState) => {
return {
counter: preState.counter + 1, //this.state.counter is 1 here
}
})
}
```
Since `setState` is an async method, if we directly `console.log` after `serState`, we'll not see the updated state. Therefore, we have to make `console.log` async as well using `setTimeout`.
```
//pure JS
let component = {
state: {
counter: 0
}
}
function setState(newState) {
//if we're passing callback function into setState
if (typeof newState === 'function') {
setTimeout(()=>{
component.state = newState(component.state)
}, 0)
} else {
//if we're just passing new state
setTimeout(()=>{
component.state = newState
}, 0)
}
}
setState((preState) => {
return {
counter: preState.counter + 1,
}
})
setTimeout(() => {
console.log(component.state.counter)
},0)
setState((preState) => {
return {
counter: preState.counter + 1,
}
})
setTimeout(() => {
console.log(component.state.counter)
},0)
```
---
#### `this` in class component
What's the correct way to define functions inside class component?
* Will this function correctly work?
```
handleAdd() {
this.setState({
counter: this.state.counter + 1,
})
}
```
=> No, this code will cause error. Because `this` is `undefined`
* Solution
1. use bind `this.handleAdd = this.handleAdd.bind(this)`
3. arrow function
---
### class component vs functional component
* class component: like a container, helps you to manage states
* functional component: helps you do the presentation
---
### HOC
**Why do we need HOC?**
Reuse lifecycle logic
**syntax**
* `parameter`: pass in an original component
* `return`: we can return a new component
```
//hoc component: withTodos
export const withTodos = (WrappedComponent) => class extends Component {
return (
<WrappedComponent
count={this.state.todos.length}
todos={this.state.todos}
addTodo={this.handlAddTodo}
removeTodo={this.handleRemoveTodo}
{...this.props}
></WrappedComponent>
)
}
//in original component
export default withTodos(OriginalComponent)
```
* Get data that's passed from parent to original child
If we want to get data from parent using props, it'll not work because the original child component is not export as original component, it's modified by HOC.
Therefore, we have to get data inside HOC, then pass it into the original child.
Using `{...this.props}` allow us to pass the whole props.
```
//Parent
<TodoList title="My Todo List"></TodoList>
//Original child
<header className="todolist-header">{this.props.title}</header>
//HOC component
```
**Disadvantage of HOC**
Without looking into the source code, we cannot know what will a HOC returns. When there're many HOCs, that'll cause issues.
```
export default withTodos(TodoList) //we have no idea what does withTodos do
```
---
### HOC v.s. Render Props
---
### Render Props
Using a `render` callback function to transfer data, it's just a concept.
**logic**
1. Create a new component `WithTodoData`
2. Move all methods inside HOC into `WithTodoData`
3. Render props can use a props called `render` to pass a function
4. We can use the function using `this.props.render()`
5. To pass data/function from render props component to original component, we can pass parameters inside `render` in RenderProps component, and setup them as props in the parent component.
```
//App component
<WithTodoData
render={(todos, addTodo, removeTodo) => (
<TodoList
todos={todos}
addTodo={addTodo}
removeTodo={removeTodo}
></TodoList>
)}
></WithTodoData>
```
```
//Render Props component
class WithTodoData extends Component {
//everything here is the same as in HOC//
render() {
return this.props.render(
this.state.todos,
this.handlAddTodo,
this.handleRemoveTodo
)
}
}
export default WithTodoData
```
And actually, we don't even need to use the `render` props, we can just use the default props `children`
```
//App
<WithTodoData>
{(todos, addTodo, removeTodo) => (
<TodoCount title="My Todo Count" count={todos.length}></TodoCount>
)}
</WithTodoData>
```
```
//Render Props component
render() {
return this.props.children(
this.state.todos,
this.handlAddTodo,
this.handleRemoveTodo
)
}
```
**Benefit**
1. Render Props can also be reused in other component just like HOC
2. A more benefic is, we can directly understand what happened just by looking at the parameters of render
**Notice**
The children of props that's passed into render props component must be a callback function, not just an object. Because we're using `this.props.children()` to use this props.
---
### coupling & decoupling
Suppose we've implemented another component that has the same structure but different style from our `Todo` component, let's call it `ColorTodo`.
We can just replace the `Todo` component with `ColorTodo` in `TodoList` component.
```
//TodoList
<ul className="todolist-items">
{this.props.todos
? this.props.todos.map((todo) => (
<ColorTodo
key={todo.id}
todo={todo}
handleRemoveTodo={() => removeTodo(todo.id)}
></ColorTodo>
))
: null}
</ul>
```
```
//App
<WithTodoData
render={(todos, addTodo, removeTodo) => (
<TodoList
title="My Todo List"
todos={todos}
addTodo={addTodo}
removeTodo={removeTodo}
></TodoList>
)}
></WithTodoData>
```
The issue is, now `Todo`&`ColorTodo` is binding inside `TodoList`, but what if we want to have different color types of TodoList, like black TodoList, which TodoList, colorful TodoList...
If `Todo` is binded inside `TodoList`, we can only have one type of TodoList. To solve this issue, we can decoupling `Todo` with `TodoList`.
**coupling & decoupling?**
```
//coupling
foo() {
foo2()
}
//de-coupling
foo(cb) {
cb()
}
foo(foo2)
```
**Re-construct**
First, use render props concept in `TodoList`.
```
//TodoList
<ul className="todolist-items">
{this.props.children(this.props.todos, this.props.removeTodo)}
</ul>
```
Then, put `Todo` as children of props in `App`.
```
//App
<WithTodoData
render={(todos, addTodo, removeTodo) => (
<TodoList
title="My Todo List"
todos={todos}
addTodo={addTodo}
removeTodo={removeTodo}
>
//use callback function as props' children here
{(todos, removeTodo) =>
todos
? todos.map((todo) => (
<ColorTodo
key={todo.id}
todo={todo}
handleRemoveTodo={() => removeTodo(todo.id)}
></ColorTodo>
))
: null
}
</TodoList>
)}
></WithTodoData>
```
In this way, if we want another `TodoList` with `Todo` component, we can just create another `TodoList`, and use `Todo` inside the component.
---
## Redux
### Intro to Redux
**What is Redux?**
A tool that helping you to manipulate the data flow.
#### Reducer
```
function counterReducer(state = { value: 0 }, action) {
switch (action.type) {
case 'counter/incremented':
return { value: state.value + 1 }
case 'counter/decremented':
return { value: state.value - 1 }
default:
return state
}
}
```
* 2 parameters:
1. state: `{ value: 0 }` is the initial state
2. action: an object
* return
a new state `{ value: state.value + 1 }`
#### store
The return object of `createStore` method. An object tree in Redux.
A store is a state container which holds the application’s state. **Redux can have only a single store in your application**. Whenever a store is created in Redux, you need to specify the reducer.
```
let store = createStore(counterReducer)
```
store has 3 methods:
1. `subscribe`: listen to the state change. If dispatch is triggered, the callback function in subscribe will be triggered once dispatch finished.
subscribe is not going to trigger the callback function. It just save the cb and trigger it after dispatch.
input: any callback function
```
store.subscribe(() => console.log(store.getState()))
//this will print current state everytime we dispatch
store.subscribe(() => console.log('hello'))
//this will print hello everytime we dispatch
```
2. `getState`: get currentState
3. `dispatch`: change state inside the store. Take an action -> send the action to reducer -> return newState to store
input: an action
**Reducer**
We can create any reducer as we want
```
function counterReducer(state = { value: 0 }, action) {
switch (action.type) {
case 'counter/incremented':
return { value: state.value + 1 }
case 'counter/decremented':
return { value: state.value - 1 }
default:
return state
}
}
```
Reducer is a pure function.
**pure function**
1. No side effect(have control to everything inside the function)
2. data imutable: cannot change the input data such as push data into the input. All the input data should be read-only.
3. same input same output
**Pure Components**
Pure Components in React are the components which do not re-renders when the value of state and props has been updated with the same values.
Ex.
```
//this is not a pure function, because add2 is not controlled by this function
function add(a) {
return add2(a)+a
}
//this is a pure function
function add2(b) {
return b
}
```
**action creater**
A function that'll return an action object.
---
> Issue: we use `Counter` component in different components: App & Header. However, the value does not change simultaneously. When we click add button at App, the Counter value at App changed, but Header's Counter remains the same.
If we want the two Counter use the same value...
> Which means, if we want to share data in different component, how could we do that?
Use Redux!
### Use Redux in components
```
import { store, actionCreater } from '../../Redux/Redux'
...
render() {
return (
<>
<h1>Counter: {store.getState().value}</h1>
<button onClick={() => store.dispatch(actionCreater.incremented())}>
Add
</button>
</>
)
}
```
#### Update UI
*Issue:* state does change, but UI is not updated. Because usually, we use `setState` to update the UI, but we don't have state here.
Therefore, to update the UI here, we have to use `forceUpdate` in the lifecycle's update phase since we don't have props nor states here.
And since it only have to be triggered once, in lifcycle, `componentDidMount` is the one that'll only be triggered once.
```
componentDidMount() {
store.subscribe(() => this.forceUpdate())
}
```
**forceUpdate in componentDidMount is repeated**
We can use HOC/render props to make this duplicated code reusable.
---
### React-Redux
Use to connect React with Redux. With React-Redux, we don't have to manually update(call subscribe) to re-render our UI, because react-redux help us do getState|dispatch|subscribe.
**connect()**
The `connect` function in react-redux is hoc. It's using currying.
```
export default connect(mapStateToProps, mapDispatchToProps)(Counter)
```
* mapStateToProps: map global(store) state to Counter props
```
//the passed in state is a global state
const mapStateToProps = (state /*, ownProps*/) => {
//thing return here will be the props to Counter
return {
counter: state.counter,
}
}
```
* mapDispatchToProps: map store dispatch to Counter props
This can be an object or method.
Object:
```
const mapDispatchToProps = { increment, decrement, reset }
```
Method:
```
const mapDispatchToProps = (dispatch /*, ownProps*/) => {
return {
add: () => dispatch(actionCreater.incremented()),
}
}
```
Looks like using react-redux, we can ignore the store, directly use methods of store.
**Modify our component using connect**
```
//Counter
<>
<h1>Counter: {this.props.counter}</h1>
<button onClick={() => this.props.add()}>Add</button>
</>
const mapStateToProps = (state /*, ownProps*/) => {
return {
//the 'value' is a state name defined in Redux
counter: state.value,
}
}
const mapDispatchToProps = (dispatch /*, ownProps*/) => {
return {
add: () => dispatch(actionCreater.incremented()),
}
}
```
**Provider**
A context API to provide you a global variable
---
### Funtional Programming | OOP Programming
React is using both. Class component is OOP concept. JSX is using Functional Programming. If using Hook&funciton all the time, it's more like functional programming.
* Funtional Programming: variables inside here should be immutable, so we usually use `const` to declare them.
---
### React-Router
---
### Context | Props | State
---
## React Hook
After React version 16.8.
### useEffect
In traditional React, we cannot use lifecycle method inside functional component. In order to use lifecycle, `useEffect()` will be triggered once React has updated the realDOM. `useEffect` is something like `componentDidMount`.
However, it's not really like `componentDidMount` that'll only be triggered once, it'll be triggered twice with lifecycles didMount&didUpdate.
> #### If we want to trigger it only related to didMount?
Use ***dependency array*** of useEffect!
In this situation, useEffect will only be triggered when the dependency array is changed.
```
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes
```
So, to make it trigger only at mount phase, we can just pass `[]` as dependency array, which will never be changed, and thus it'll only run once.
#### How can we have one useEffect for mount and another for only update?
```
//create a ref to know whether it's first mount
let mountRef = useRef(false)
useEffect(() => {
console.log('mount')
}, [])
//this can make sure it only trigger after data is updated
useEffect(() => {
if (!mountRef.current) {
mountRef.current = true
} else {
console.log('update')
}
})
```
### useState
It's using destructure.
*input*: initial value, if put nothing, it's undefined
*return*: array
```
const [counter, setCounter] = useState(0)
//is equal to
const result = useState(0)
const counter = result[0]
const setCounter = result[1]
```
two ways of initializing state:
```
//But this one is better because more flat(less nested)
const [counter, setCounter] = useState(0)
const [isLoading, setIsLoading] = useState(true)
//is basically equal to
const [counterObj, setCounterObj] = useState({
counter: 0,
isLoading: false,
})
```
However, later on when we want to change only `counter` value and we call `setCounterObj({isLoading: false})`, the `counter` property will be removed, it'll not automatically copy the `counter` property for us like what `setState` does.
### How Hooks works
Here's a tricky example
```
//hook component
import { useEffect, useState } from 'react'
export function HookApp() {
const [count, setCounter] = useState(0)
return (
<section className="hooksApp">
<h1>Hook App</h1>
<div>count: {count}</div>
<button onClick={() => setCounter(count + 1)}>Add One</button>
<button
onClick={() =>
setTimeout(() => {
alert(count)
}, 3000)
}
>
Alert
</button>
</section>
)
}
//class component
import React from 'react'
export class ClassApp extends React.Component {
state = {
count: 0
}
render() {
return (
<section className="classApp">
<h1>Class App</h1>
<div>count: {this.state.count}</div>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Add One
</button>
<button
onClick={() =>
setTimeout(() => {
alert(this.state.count)
}, 3000)
}
>
Alert
</button>
</section>
)
}
}
```
If we click Alert button and add one for both components, after 3 secs, the class component will alert 1 for the count but hook component will alert 0.
**Why?**
class component's initial phase will be triggered only once, after that, we have the instance. Therefore, when we call `this.state`, we're refering to the state, with updated value.
But functional component with hooks will invoke JSX to re-generate the whole initial component everytime when we change data. Everything inside the hook component is immutable.
Solution1: create a global variable
Solution2: useRef
### useRef
Help us share data between hooks
What useRef return will be the previous state's hook value
```
const [counter, setCounter] = useState(0)
let counterRef = useRef(counter)
console.log(counterRef)
>>> {current: 0}
//to make counterRef change with counter
counterRef.current = counter
```
In this way, we can save data into ref, and it'll not be refreshed everytime data changes.
---
## Flux
architecture pattern
---
## TypeScript
React was using propType type system.
---