### JavaScript Classes
### +
### Introduction to React.js

Spring 2019 。 Ric Huang
---
### **Classes** in ES-6
* JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugars over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript. [[ref](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)]
----
### Class Declarations
```javascript
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
```
// Compared to ---
```javascript
function Rectangle(height, width) {
this.height = height;
this.width = width;
}
```
----
### No class hoisting!!
```javascript
const p = new Rectangle(); // ReferenceError!!
class Rectangle {}
```
----
### Class Methods
```javascript
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Method
calcArea() {
return this.height * this.width;
}
}
const a = new Rectangle(10, 20);
a.calcArea(); // 200
```
----
// Compared to ---
```javascript
function Rectangle(height, width) {
this.height = height;
this.width = width;
this.calcArea = function () {
return this.height * this.width;
}
}
const a = new Rectangle(10, 20);
a.calcArea();
```
----
### With get/set methods
```javascript
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() { return this.calcArea(); }
// Method
calcArea() { return this.height * this.width; }
}
const a = new Rectangle(10, 20);
a.calcArea(); // 200
a.area; // 200
```
// See "[getter/setter methods for objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters)"
(not for "functions")
----
### Static Methods
* Static methods are called without instantiating their class and **cannot** be called through a class instance.
* Static methods are often used to create utility functions for an application.
```javascript
class Point {
constructor(x, y) { this.x = x; this.y = y; }
static distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy);
}
}
const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
console.log(Point.distance(p1, p2)); // 7.0710678118654755
```
----
### Be careful about "this", again!
* In the above example, since there is no caller object when "Point.distance(p1, p2)" is called, no **this** is defined!
----
### Class Inheritance
* Using the keywords **extends** and **super**
```javascript
class Animal {
constructor(name) { this.name = name; }
speak() { console.log(this.name + ' makes a noise.'); }
}
class Dog extends Animal {
constructor(name) {
super(name); // call the super class constructor and
// pass in the name parameter
}
// Overload parent class' method
speak() { console.log(this.name + ' barks.'); }
}
let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
```
----
### Recall: Inheritence with "function"
```javascript
function Animal(name) {
this.name = name;
this.speak = function () {
console.log(this.name + ' makes a noise.');
}
}
function Dog(name) {
Animal.call(this, name);
this.speak = function() {
console.log(this.name + ' barks.');
}
}
Dog.prototype = Object.create(Animal.prototype);
let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
```
----
### FYI: Function.prototype.call() ([ref](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call))
* The **call()** method of **Function** calls a function with a given this value and arguments provided individually.
```javascript
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
// expected output: "cheese"
```
----
### Or, mixed function and class...
```javascript
function Animal (name) { this.name = name; }
Animal.prototype.speak = function () {
console.log(this.name + ' makes a noise.');
}
class Dog extends Animal {
speak() {
console.log(this.name + ' barks.');
}
}
let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
```
----
### But, can't extend from object!!
```javascript
const Animal = {
speak() {
console.log(this.name + ' makes a noise.');
}
};
// Error!!
class Dog extends Animal {
constructor(name) {
super(name); // call the super class constructor and
// pass in the name parameter
}
speak() { console.log(this.name + ' barks.'); }
}
```
----
### Unless you use Object.setPrototypeOf()
```javascript
Object.setPrototypeOf(Dog.prototype, Animal);
let d = new Dog('Mitzie');
d.speak(); // Mitzie makes a noise.
```
----
### Calling super class's method
* Again, using **super**
```javascript
class Cat {
constructor(name) { this.name = name; }
speak() { console.log(`${this.name} makes a noise.`); }
}
class Lion extends Cat {
speak() { super.speak(); console.log(`${this.name} roars.`);}
}
let l = new Lion('Fuzzy');
l.speak();
// Fuzzy makes a noise.
// Fuzzy roars.
```
---
### You've learned "class" in JavaScript.
### How can it help you?
----
### Let's construct a simple table

* Download pure HTML implementation from: [link](https://github.com/ric2k1/ric2k1.github.io/blob/master/W5_0320/practice/class-practice.tgz)
----
### Think: If there are going to be more columns and rows, the HTML file can become very long and thus hard to maintain.
----
### Make the "repeated" structures into "class" instances
```htmlembedded
<!-- <thead> -->
<tr>
<th>Subject</th>
<th>Score</th>
</tr>
<!-- <tbody> -->
<tr>
<td>Math</td>
<td>100</td>
</tr>
<tr>
<td>Chinese</td>
<td>87</td>
</tr>
```
* What are the repeated structures?
----
### How to design a class?
* class name?
* What will be constructed? // i.e. class properties
* constructor input(s)?
```htmlembedded
<!-- <thead> -->
<tr>
<th>Subject</th> <th>Score</th>
</tr>
<!-- <tbody> -->
<tr>
<td>Math </td> <td>100 </td>
</tr>
<tr>
<td>Chinese</td> <td>87 </td>
</tr>
```
----
### Who instantiates the class, and how?
* theadNode.appendChild(new Row(...)...);
* tbodyNode.appendChild(new Row(...)...);
----
### In-class practice!
----
### How do "class" help you?
* Any better way to write the code and make it cleaner and more extensible (maybe more object-oriented)?
---
### Introduction to React.js
----
### Preparations
* Install "create-react-app"
* (建議) node.js & npm 要先安裝
* sudo npm install -g create-react-app
* In case you encounter any problem, use [CodePen](https://reactjs.org/redirect-to-codepen/hello-world) instead **for now**...
----
### Before learning React
* 如果說,前四個星期教的 HTML, CSS, JavaScript 讓你學會怎麼去寫一個簡單的網頁程式,那麼,從這星期開始教的 React, 以及後面眾多單元,將會真正帶你進入 "Web Applications" 的奇幻旅程!
* 不只是學寫程式,而要去 **「了解整個技術生態系,從服務設計的思維出發,學會使用最佳的工具與資源,進行最有效率的設計與開發!」**
----
### 從 React 看整個技術生態系[[ref](https://github.com/kdchang/reactjs101/blob/master/Ch01/react-ecosystem-introduction.md)]
* JSX
* Node.js, npm
* Babel
* CommonJS 等模組化開發
* Webpack
* ESLint
* React Router
* Flux, Redux
* Jest
* React Native
* GraphQL/Relay
----
### 兩個月後回來,希望你對於上一頁的所有技術都暸若指掌了!
---
### React.js [[wiki](https://en.wikipedia.org/wiki/React_(JavaScript_library))]
* React is a JavaScript library.
* 目前由 Facebook 以及 reactjs.org 所維護
* 前端。single-page application
* First developed by Jordan Walke of Facebook in 2011, and opened source in May 2013.
* React Native was released and opened source in 2015, which enabled native Android and IOS development with React
----
### Your First React Program
```
> create-react-app hello-world
> cd hello-world
> npm start
```
#### What did you see?
----
### Check these files
* public/index.html
* src/index.js
* src/App.js
----
### What did "create-react-app" do for you?
```
npm init projectName
npm install
// what you need to run React,
// including all the modules, webpack configure, Babel... etc
And prepare all scripts for you to run React Apps
```
* If you click to open "index.html" in browser, what did you see?
----
### Edit the file "src/App.js" to print out "Hello, World!"
* Delete lines 8-23
* Change returned context to "\<h1>Hello, world!\</h1>"
* Save it, and you will see the webpage automatically reloaded!
----
### Or, simply do ---
* Change this line in "index.js":
```jsx
ReactDOM.render(
<App / >, document.getElementById('root'));
```
* to ---
```jsx
// App.js won't be called
ReactDOM.render(
<h1>Hello, world!</h1>, document.getElementById('root'));
```
----
### Try to explain what you see!
---
### React Basics
* React 是一種 component-based 的寫法 ---
把網頁的 DOM 想成一個個的 components, 然後利用 **JSX** 的語法,把每個 component 寫成 **React element**, 就像是在 JavaScript 裡頭直接寫 HTML 一樣,然後利用 **ReactDOM** 的 **render()** method 把 React element 畫到 index.html 對應的節點上面:
```jsx
// In JavaScript/React
ReactDOM.render(
<h1>Hello, world!</h1>, document.getElementById('root'));
```
```htmlembedded
<!-- In HTML -->
<body>
<div id="root"></div>
</body>
```
----
### Virtual DOM
* JavaScript 裡頭對於 DOM element 的產生與操作是很慢的;React 則使用了 Virtual DOM 的概念,去 monitor 頁面改變的地方,而當改變發生的時候,只重新 render 改變部分,因此,可以大幅提升畫面更新的速度
* Recall: How you insert/delete an item in "TODO list" homework?
----
### "Classes" in React
* 上面的範例也可以用 React 的 **"class"** 來改寫
```jsx
class Hello extends React.Component {
// 一定要有一個 render() method
render() {
// 回傳很像是 html 的 jsx
return <h1>Hello, World</h1>;
}
}
```
* 然後在 JS 的主程式
```jsx
ReactDOM.render(
<Hello / >, document.getElementById('root'));
```
----
### Quick Summary -- How React works?
* 用 HTML 把網頁的殼子畫出來
* 用 JSX 的語法定義 React elements (as DOM components)
```jsx
// expression
<tag>text or { expression }</tag>
// or class
class ClassName extends React.Component {
render() { ... return...; }
}
```
* ReactDOM.render(element, node);
----
### ReactDom.render()
* 語法
```jsx
ReactDOM.render(element, container[, callback]);
```
* 其中 **element** 除了可以直接把 JSX 語法寫在參數上面之外,也可以是一個 JavaScript 的 variable:
```jsx
let e = <h1>Hello, world!</h1>;
ReactDOM.render(e, document.getElementById('root'));
```
* 而 **container** 則是一個 DOM node
* **callback** 顧名思義則是在 render() 完成後被呼叫
---
### JSX (JavaScript XML)
* An extension to the JavaScript language syntax to provide a way to structure component rendering using syntax familiar to many developers (i.e. HTML/XML).
----
### JSX to create React Elements
* JSX 背後其實是用 React.createElement() 去做轉換的
```jsx
// Input (JSX):
var app = <Nav color="blue" />;
// Output (JS):
var app = React.createElement(Nav, {color:"blue"});
```
```jsx
// Input (JSX):
var app = <Nav color="blue"><Profile>click</Profile></Nav>;
// Output (JS):
var app = React.createElement(
Nav,
{color:"blue"},
React.createElement(Profile, null, "click")
);
```
----
### Embedding JS Expressions into JSX
* 可以在適當的地方用 {…} 插入任何 JavaScript 的 expressions:
```jsx
const e1 = <h1> Hello, {iAmAFunction(pp)}! </h1>;
const e2 = <img src={user.avatarUrl}></img>;
const e3 = <p> 2 + 3 = { 2+3 } </p>
let e4;
if (someExp) e4 = <h1>Hello, {iAmAFunction(pp)}!</h1>
else e4 = <h1>Hello, world!</h1>
```
----
### Specifying Tag Attributes with JSX
* 指定 JSX tag 裏頭 attribute 的值
// 請注意,JSX 裏頭 tag 的名稱為了不要跟 JavaScript 裏頭的保留字衝突,會換成別的名稱,且會變成 CamelCase
```jsx
<div className="foo" /> // as "class" in HTML
<label htmlFor="username">Username</label> // as "for" in HTML
<MyButton disabled={false} onClick={() => {}} />
```
----
### 常犯錯誤
```jsx
render() { // 不能回傳並列的 elements
return (
<div>Hello 1</div>
<div>Hello 2</div>
);
}
```
* 應該只能有一個 root element
```jsx
render() { // 包進 div
return (
<div>
<div>Hello 1</div>
<div>Hello 2</div>
</div>
);
}
```
----
### 常犯錯誤
* 用 " " 把 { } 的 JS expression 括起來 => 會變字串
* 用 ( ) 把 { } 的 JS expression 括起來 => 會多生出 ( ) 符號,或者是文法錯誤!
* 或是忘記加 { }
```jsx
<A disabled="{false}" onClick={() => {}} /> // extra { }
<A> ({ "World!" }) </A> // extra ( ); output: (World!)
<A> ("World!") </A> // Missing { }; output: ("World!")
<A> { "World!"; } </A> // NO statement; ERROR: extra ';'!
```
---
### More React Components
* 就像是 JavaScript 利用 function/class 來定義一個 object 的 prototype; React 也可以利用 function/class 來定義 React element 的 prototype
// function 的用法,not recommended
```jsx
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
```
* **'props'** 是保留字,用來指定 React component 的 properties, 不要隨便換名字
----
### React Components with class properties
* 用 class 裡頭的 this.props 來承接各種 component 的 properties (e.g. name), 然後在外部的 instantiation 利用 tag value assignment 來指定 property value
// 建議用法
```jsx
import React, { Component } from 'react';
class Welcome extends Component {
render() { return <h1>Hello, {this.props.name}</h1>; }
}
const element = <Welcome name="Ric" / >;
ReactDOM.render(element, document.getElementById('root'));
```
---
### 搞得我好亂啊!到底是在寫 JS, JSX, 還是 HTML... !%#&^%@&$%@!
----
### Rules of thumb
* 到底是 JSX, 還是 JS? Browser 的 interpreter engine 會幫你分辨,基本上:
* 這是 .js 檔,所有的語法要 follow JS
* 但當某個 expression 被 HTML-like tag (e.g. <ScoreCard>) 包起來的時候,就進入了 JSX 的範疇,你要以 JSX 的語法來寫,像是:
* <tag>what to be shown</tag>
* <tag>something { JS expression } </tag>
* 多餘的 { }, " ", ( ) 都有可能變成 viewable 的一部分 (e.g. <tag>(extra braces)</tag>)
----
### Let's do some Practice

* What's the DOM structure for this example?
----
### Let's first see how the data is stored
* Make the record extensible, and can be applied to other students
```javascript
const columnIndex = [ 'Subject', 'Score' ];
const scoreCard = {
name: 'Ric',
records: [
[ 'Math', 100 ],
[ 'Chinese', 87 ],
[ 'English', 100 ],
[ 'Science', 100 ],
[ 'Social', 0 ]
]
};
```
----
### Change index.html
* Make a "root" ready for ReactDOM components
```htmlembedded
<body>
<!-- will insert ReactDOM component here -->
<!-- wrap the <table> with a <div> -->
<div id="root"></div>
</body>
```
----
### Link JSX to HTML
```jsx
// In "index.js"
ReactDOM.render(<ScoreCard scoreCard = {scoreCard}
columnIndex = {columnIndex} / >,
document.getElementById('root'));
```
* scoreCard is the attribute name of the class \<ScoreCard>
* {scoreCard} refers to the variable in JS, so { } is needed
----
### Define "class ScoreCard"
```jsx
// in App.js
class ScoreCard extends Comonent {
render() {
return (
<table>
...
</table>
);
}
}
```
* Next, let's use JSX to generate a ReactDOM element for \<table>
----
### From data to ReactDOM element
```jsx
const columnIndex = [ 'Subject', 'Score' ];
const scoreCard = {
name: 'Ric',
records: [
[ 'Math', 100 ],
[ 'Chinese', 87 ],...
]
};
```
```jsx
return (
<table>
<caption> Ric's Score </caption>
<thead>
<tr><th> Subject </th><th> Score </th></tr>
</thead>
<tbody>
<tr><td> Math </td><td> 100 </td></tr>
<tr><td> Chinese </td><td> 87 </td></tr>...
</tbody>
</table>
);
```
----
### \<caption>
<br>
```jsx
<caption> {this.prop.scoreCard.name}'s Score </caption>
```
----
### \<thead>
```jsx
// From
cosnt columnIndex = [ 'Subject', 'Score' ];
// To
<thead>
<tr><th> Subject </th><th> Score </th></tr>
</thead>
```
// Commnet out solution for lecture
<!--
```jsx
<thead>
<tr>
{ this.props.columnIndex.map( e => <th>{e}</th> ) }
</tr>
</thead>
```
-->
----
### \<tbody>
```jsx
// From
const scoreCard = {
name: 'Ric',
records: [
[ 'Math', 100 ],
[ 'Chinese', 87 ],...
]
};
// To
<tbody>
<tr><td> Math </td><td> 100 </td></tr>
<tr><td> Chinese </td><td> 87 </td></tr>...
</tbody>
```
----
### Think of it in a JSX way...
```jsx
// From
const scoreCard = {
name: 'Ric',
records: [
[ 'Math', 100 ],
[ 'Chinese', 87 ],...
]
};
// Or put it this way...
<tbody>
[ <tr>[ Math, 100 ]</tr>,
<tr>[ Chinese, 87 ]</tr>,...
]
</tbody>
```
----
### Reference solution
// Commnet out solution for lecture
<!--
```jsx
let records = this.props.scoreCard.records.map
( e => e.map( g => <td>{g}</td> ) );
// This will create:
// [ [ subjectNode, scoreNode]...], where
// subjectNode = <td>{'subject'}</td>,
// scoreNode = <td>{ score }</td>
// In the return part...
<tbody>{ records.map( e => <tr>{e}</tr>) }
```
-->
----
## Did you make it?
---
### Take-Home Practice03
* Make a **static** blog page.
* You don't need to implement "edit", "post", "add/delete", "search", or any kind of interactions.
* Just a static page that is composed of title, menu, sections, articles or photos, etc.
* Use **React** to make it component-based so that you can add more interactions later!
---
### Next Week -- More on React.js
* propTypes
* props and state
* React Event Handlers
* Component Lifecycle
---
### React Reference Readings
* From official reactjs.org website
* [Getting started](https://reactjs.org/docs/getting-started.html)
* [A short tutorial](https://reactjs.org/tutorial/tutorial.html)
* [Thinking in React](https://reactjs.org/docs/thinking-in-react.html)
----
* **React Fundamentals**: 不錯且都很短的教學影片
* [Hello World - First Component](https://egghead.io/lessons/react-hello-world-first-component)
* [The Render Method](https://egghead.io/lessons/react-the-render-method)
* [Introduction to Properties](https://egghead.io/lessons/react-introduction-to-properties)
* [State Basics](https://egghead.io/lessons/react-state-basics)
* [Owner Ownee Relationship](https://egghead.io/lessons/react-owner-ownee-relationship)
* [Using Refs to Access Components](https://egghead.io/lessons/react-using-refs-to-access-components)
* [Accessing Child Properties](https://egghead.io/lessons/react-accessing-child-properties)
* [Component Lifecycle - Mounting Basics](https://egghead.io/lessons/react-component-lifecycle-mounting-basics)
* [Component Lifecycle - Mounting Usage](https://egghead.io/lessons/react-component-lifecycle-mounting-usage)
* [Component Lifecycle - Updating](https://egghead.io/lessons/react-component-lifecycle-updating)
---
## That's it!
{"metaMigratedAt":"2023-06-14T20:39:20.913Z","metaMigratedFrom":"YAML","title":"JavaScript Classes + Intro to React.js (03/20)","breaks":true,"slideOptions":"{\"theme\":\"beige\",\"transition\":\"fade\",\"slidenumber\":true}","contributors":"[{\"id\":\"752a44cb-2596-4186-8de2-038ab32eec6b\",\"add\":21290,\"del\":2453},{\"id\":\"80884e44-250e-4767-9a04-440ae2901368\",\"add\":1,\"del\":0},{\"id\":\"a202b02b-072b-4474-be14-c5a3f8932dbb\",\"add\":4,\"del\":5}]"}