### JavaScript Classes ### + ### Introduction to React.js ![](https://i.imgur.com/t3iiJHK.png) 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 ![](https://i.imgur.com/rpVQJCM.png) * 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 ![](https://i.imgur.com/rpVQJCM.png) * 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}]"}
    2465 views