
---
# (H)尊絕不凡 React 教學
## - 第一週
---
### 很感謝大家都「願意」來上課。
---
### 忍忍,很快就過去了。
---
我是接下來的講者
### 吳其聯 Robby
- Github [https://github.com/explooosion](https://github.com/explooosion)
- Blog [https://dotblogs.com.tw/explooosion](https://dotblogs.com.tw/explooosion)
---
### 在開始前
1. 盡量不要晃動。
2. 如果覺得很難是正常的。
3. 如果看不懂沒關係,再讀一次,相信我。
4. 建議做筆記。
---
### 學習目標
1. 現代WEB開發觀念(since 2009)
2. React 介紹與環境
3. React TodoList
---
### 環境確認
1. node.js
2. git
3. yarn
4. vscode
5. wifi
6. Windows 關閉自動更新
---
### VScode Extension
1. Auto Rename Tag
2. Babel ES6/ES7
3. DotENV
4. ESLint (`npm install eslint -g`)
5. FileNameComplete
6. HTML Snippets
7. IntelliSense for CSS class names in HTML
8. Path Intellisense
9. Sass
---
### Chrome Extension
1. [React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi)

---
# 開始上課囉
---

---
### 在什麼都不懂前
我們先體驗看看 React
- [facebook/create-react-app](https://github.com/facebook/create-react-app)
請大家輸入以下指令:
```shell=
npx create-react-app my-app
cd my-app
npm start
```
---
#### 靜態不好看,給你看動態的。

---
#### 指令說明

---
## 到 vscode 介紹環境
小抄:
1. 目錄結構
2. package
3. entrypoint
4. index.html
5. index.js
6. manifest.json(PWA)
8. test
9. gitignore
---
## 現代化 Web 開發觀念
---
### 名詞與套件解釋
1. 模組化
2. ES6+
3. SPA
4. Client Side Rendering
5. Server Side Rendering
6. Webpack
7. Babel
8. ESLint
9. Pure Function
10. Functional Programming(FP)
---
#### 開始講歷史

---
#### 1. 模組化 - 無模組化
- jQuery 2006年1月釋出
- 嚴重的污染問題。
```htmlmixed=
<script src="jquery.js"></script>
<script src="jquery_scroller.js"></script>
<script src="main.js"></script>
<script src="other1.js"></script>
<script src="other2.js"></script>
<script src="other3.js"></script>
```
---
#### 1. 模組化 - CommonJS 規範

---
#### 1. 模組化 - CommonJS 規範
- Mozilla 工程師Kevin Dangoor 於2009年1月創建 ServerJS
- 2009年8月,改名為CommonJS(革命)
- 為了解決JavaScript 作用域問題
- 適用於伺服器端,同步處理
- Node.js 使用此規範
---
#### 1. 模組化 - CommonJS 規範
在JS中新增「require」以及「export」物件。
建立
```javascript=
// a.js
var x = 5;
var addX = function (value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
```
引入
```javascript=
var example = require('./a.js');
console.log(example.x); // 5
console.log(example.addX(1)); // 6
```
---
#### 1. 模組化 - CommonJS 規範
因為資源的獲取所需的時間不確定,瀏覽器需要端異步機制:
- 基於 AMD 的 RequireJS
- 基於 CMD 的 SeaJS
---
#### 1. 模組化 - AMD 規範(requirejs)

---
#### 1. 模組化 - AMD 規範(requirejs)
使用「define」、「require」。
```javascript=
define(function () {
var alertName = function (str) {
alert("I am " + str);
}
var alertAge = function (num) {
alert("I am " + num + " years old");
}
return {
alertName: alertName,
alertAge: alertAge
};
});
```
```javascript=
require(['alert'], function (alert) {
alert.alertName('JohnZhu');
alert.alertAge(21);
});
```
---
#### 1. 模組化 - CMD 規範(seajs)

---
#### 1. 模組化 - CMD 規範(seajs)
```javascript=
define(function(require, exports, module) {
var $ = require('jquery');
var Spinning = require('./spinning');
exports.doSomething = ...
module.exports = ...
})
```
---
### 1. 模組化 - ES6 規範
- 2015年6月,ECMAScript2015 發布 ES6
- 利用 import、export 就可以模組化
- 但目前大多(99%)瀏覽器和Node.js 不支援...
- 可以通過Babel 將寫好的 ES6 轉換為 ES5
---
#### 1. 模組化 - ES6 規範
```javascript=
import store from '../store/index'
import { mapState, mapMutations, mapActions } from 'vuex'
import axios from '../assets/js/request'
import util from '../utils/js/util.js'
export default {
created () {
this.getClassify();
this.RESET_VALUE();
console.log('created' ,new Date().getTime());
}
```
---
#### 2. ES6 - map
- map() 方法會建立一個新的陣列,其內容為原陣列的每一個元素經由回呼函式運算後所回傳的結果之集合。
```javascript=
var array1 = [1, 4, 9, 16];
// pass a function to map
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
```
---
#### 2. ES6 - filter
- filter() 方法會建立一個經指定之函式運算後,由原陣列中通過該函式檢驗之元素所構成的新陣列。
- 如果條件都不符合,**會是一個空的陣列**
```javascript=
var words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]
```
---
#### 2. ES6 - find
- find() 方法會回傳第一個滿足所提供之測試函式的元素值。
- 都找不到則為 **undefined**。
```javascript=
var array1 = [5, 12, 8, 130, 44];
var found = array1.find(element => element > 10);
console.log(found);
// expected output: 12
```
---
#### 2. ES6 - reduce
- reduce() 方法將一個累加器及陣列中每項元素(由左至右)傳入回呼函式,將陣列化為單一值。
```javascript=
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10
// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15
```
---
#### 2. ES6 - 簡化屬性描述 (Shorthand Property Names)
```javascript=
function getStudent(chemistry, biology, mathematics) {
return {
// [屬性名稱] 與 [屬性值變數名稱] 相同的時候
chemistry: chemistry, // ES5 只能這樣做
biology, // ES6 可以此表示 biology: biology
math: mathematics , // 不同名稱當然就只能這樣囉
// 以更精簡方式宣告 funcion
getScore() {
return this.chemistry + this.biology + this.math
}
}
}
```
---
#### 2. ES6 - 解構賦值 (Destructuring Assignment)

---
#### 2. ES6 - 解構賦值 (Destructuring Assignment)
```javascript=
// [範例1] 在 function 中只取出需要的傳入值
var student = { name: 'chris', age: 15 }
showStudentInfoES6(student)
function showStudentInfoES6 ({ name, age: hisAge }) {
console.log('name: ', name) // -> name: chris
console.log('hisAge:', hisAge) // -> hisAge: 15
}
```
---
#### 2. ES6 - 模組 (Module)
```javascript=
/* utility.js */
const timeout = 200
function addNumber(...nums){
var result = 0
nums.forEach(function (number) {
result += number
})
return result
}
export {timeout, addNumber}
```
```javascript=
/* other.js */
import { addNumber } from './utility.js'
console.log(addNumber(1, 2)) // -> 3
```
---
#### 2. ES6 - React 風格模組
```javascript=
/* myComponent.js */
export default class MyComponent extends React.Component {
// ...
}
```
```javascript=
/* header.js */
import MyOwnNameComponent from './myComponent'
const header = props => {
return <div>
<MyOwnNameComponent />
</div>
}
export default header
```
---
#### 2. ES6 - 其餘屬性 (Rest Properties)
或稱為:剩餘參數
```javascript=
// 測試物件
var person = { name: 'chris', age: 19, isMarried: true }
// 簡單的將剩餘屬性存放在 otherInfo 中
var { name, ...otherInfo } = person
console.log(name) // -> chris
console.log(otherInfo) // -> { age: 19, isMarried: true}
```
---
#### 2. ES6 - 展開屬性 (Spread Properties)
很常用在更新一些物件屬性。
```javascript=
// 測試物件
var person = { name: 'chris', age: 19, isMarried: true }
console.log( {...person} ) // -> { name: 'chris', age: 19, isMarried: true }
console.log( person === {...person} ) // -> false, 是新物件唷
// 展開 person 屬性並與新 age 屬性值合併輸出新物件
function changeAge (person, newAge) {
return { ...person, age: newAge }
}
console.log(changeAge(person, 10))
// -> { name: "chris", age: 10, isMarried: true }
```
---
#### 2. ES6 - 字串樣板 (String Template)
或稱文字樣板、樣版引擎
```javascript=
var first = 'chris', last = 'chen'
var _name = 'your name is ' + first + ' ' + last
var name = `your name is ${first} ${last}.`
console.log(name) // -> 'your name is chris chen.'
```
---
#### 2. ES6 - 箭頭函數 (Arrow Functions)
```javascript=
// 傳統的方法宣告方式
function square(value){
return value*value
}
// 使用 arrow function 改寫
// 參數: 使用 () 包住
// 內容: 寫在 {} 裡面
var square1 = (value) => {return value*value}
// 特定情境下使用 arrow function 可以更加精簡
// 參數: 只有在單個參數時才可以省略 ()
// 內容: 只有在單個 statement 且是回傳值時才可以省略 {} 及 return 文字
var square2 = value => value*value
// 若要直接回傳物件時,使用 () 包住物件即可
// 順便複習使用簡寫特性表示 {name:name, phoneNo:phoneNo}
var buildContact = (name, phoneNo) => ({name, phoneNo})
// 測試一下囉
console.log(square1(2)) // -> 4
console.log(square2(2)) // -> 4
console.log(buildContact('chris','0911123123'))
// -> {name:"chris", phoneNo: "0911123123"}
```
---
#### 3. SPA
Single Page Application(SPA)
單一頁面應用程式
1. Bundle
2. Router
3. SEO
4. F12
5. AJAX
---
#### 4. Client Side Rendering

---
#### 5. Server Side Rendering

---
#### 6. Webpack

---
#### 6. Wepback - 功能
1. 將你的 js 檔案 Bundle 變成單一的檔案
2. 在你的前端程式碼中使用 npm packages
3. 撰寫 JavaScript ES6 或 ES7+(需要透過 babel 來幫助)
4. Minify 或優化程式碼
5. 將 LESS 或 SCSS 轉換成 CSS
6. 使用 HMR(Hot Module Replacement)
7. 包含任何類型的檔案到你的 JavaScript
---
#### 6. Webpack - 與其他比較
在還沒有 Webpack 之前: Grunt, gulp

---
#### 7. Babel@7.x.x
Babel is a JavaScript compiler.
Use next generation JavaScript, today.

---
#### 8. ESLint
ESLint 是一個 Javascript Linter,
他能確保你的程式碼品質在一定的水準之上。

---
#### 8. ESLint - 功能
1. 幫你找出語法錯誤
2. 確保你遵循最佳實踐
3. 提醒你刪掉多餘的程式碼
4. 統一基本的 coding style
---
#### 8. ESLint - 安裝
```shell=
npm install eslint -g
```

---
#### 8. ESlint - 規則
airbnb code style
```javascript=
// bad
var a = 1;
var b = 2;
// good
const a = 1;
const b = 2;
```
```javascript=
// bad
const item = new Object();
// good
const item = {};
```
---
#### 8. ESlint - 規則
```javascript=
// bad
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
};
```
---
#### 8. ESlint - 規則
```javascript=
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
};
// good
const obj = {
lukeSkywalker,
};
```
---
#### 8. ESlint - 規則
```javascript=
// bad
const items = new Array();
// good
const items = [];
```
---
#### 8. ESlint - 規則
```javascript=
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
// good
function getFullName(user) {
const { firstName, lastName } = user;
return `${firstName} ${lastName}`;
}
// best
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
```
---
#### 8. ESlint - 規則
```javascript=
// bad
const name = "Capt. Janeway";
// bad - template literals should contain interpolation or newlines
const name = `Capt. Janeway`;
// good
const name = 'Capt. Janeway';
```
---
#### 8. ESlint - 參考聖經
[https://github.com/airbnb/javascript](https://github.com/airbnb/javascript)
---
#### 9. Pure Function
純(粹)函數
將相同的input丟入函式,永遠會回傳相同的output結果。
```javascript=
// 純函數
function priceAfterTax(productPrice) {
return (productPrice * 0.2) + productPrice;
}
```
```javascript=
// 非純函數
var tax = 20;
function calculateTax(productPrice) {
return (productPrice * (tax/100)) + productPrice;
}
```
---
#### 10. Functional Programming
函數式程式設計
```javascript=
// inc everything and sum
let array = [1, 2, 3, 4, 5]
// foreach
let sum = 0
for (let el of array) {
sum += el + 1
}
// functional way
let sum = array
.map(x => x + 1)
.reduce((acc, el) => acc + el, 0)
```
---
#### 10. Functional Programming - 御三家

---
#### 10. Functional Programming - FP 御三家
- Map
- Filter
- Reduce
---
### React 生態系(Ecosystem)入門簡介
---
#### React - logo

---
#### React - 簡介
- React專注於UI(View)。
- Facebook於2013年開源React。
---
#### React - 設計理念
1. Declarative (實現宣告式or聲明式)
2. Component-Based
3. Learn Once, Write Anywhere
---
#### 補充:Imperative vs Declarative
Imperative 命令式 - How(如何)
Declarative 聲明式 - What(甚麼)
---
我們用 FB 讚的樣式設計解釋:
- 已讚:藍色
- 未讚:灰色

---
#### 補充:Imperative
- Imperative是告訴程式如何做(How)一些事,其實就是平日programming常做的,你寫下指示,程式一步一步跟隨你的指示做。
```javascript=
if(userLikes()) {
if(!hasBlueLike()) {
removeGrayLike();
addBlueLike();
}
} else {
if(hasBlueLike()) {
removeBlueLike();
addGrayLike();
}
}
```
---
#### 補充:Declarative
- Declarative 聲明你需要甚麼(What),不用理會程式用甚麼方法、甚麼步驟做到。
```jsx=
if(this.state.liked) {
return (<BlueLike>);
} else {
return (<GrayLike>);
}
```
---
### React 生態系(Ecosystem)入門簡介
---
#### React 生態系(Ecosystem)

- webpack
- react
- redux/flux
- react-router
---
### ReactJS 與 Component 設計入門介紹
---
### ReactJS 特性簡介
1. 基於元件(Component)化思考
2. 用 JSX 進行聲明式(Declarative)UI 設計
3. 使用 Virtual DOM
4. Component 狀態機(State Machine)&生命週期(Life Cycle)
5. 一律重繪(Always Redraw)和單向資料流(Unidirectional Data Flow)
6. 在 JavaScript 裡寫 CSS:Inline Style
---
#### 1. Component

---
#### 1. Component
在 React 的世界中最基本的單元為元件(Component),並依照需求組裝成一個組合式的(Composable)元件。
- 封裝(encapsulation)
- 關注點分離 (Separation of Concerns)
- 複用 (Reuse)
- 組合 (Compose)。
---
#### 1. 一般 React Component 撰寫
使用 ES6 的 Class
```jsx
// 注意元件開頭第一個字母都要大寫
class MyComponent extends React.Component {
// render 是 Class based 元件唯一必須的方法(method)
render() {
return (
<div>Hello, World!</div>
);
}
}
// 將 <MyComponent> 元件插入 id 為 app 的 DOM 元素中
ReactDOM.render(<MyComponent>, document.getElementById('app'));
```
---
#### 1. 一般 React Component 撰寫
使用 Functional Component 寫法
```jsx
const MyComponent = () => (
<div>Hello, World!</div>
);
// 將 <MyComponent> 元件插入 id 為 app 的 DOM 元素中
ReactDOM.render(
<MyComponent>,
document.getElementById('app')
);
```
---
#### 2. JSX 聲明式(Declarative)設計
```jsx
// 使用宣告式(Declarative)UI 設計很容易可以看出這個元件的功能
<MailForm>
```
```jsx
// <MailForm /> 內部長相
<form>
<input type="text" name="email" />
<button type="submit"></button>
</form>
```
---
#### 3. 使用 Virtual DOM

---
#### 4. Component 特性
1. State Machine: state 和 props(由父元素傳入)
2. Life Cycle: 可以在對應的時間點進行 Component 需要的處理
---
#### 5. 重繪和資料流
1. props 都是由父元素所傳進來,不能更改,若要更改 props 則必須由父元素進行更改
2. 當 React 發現 props 或是 state 更新時,就會重繪整個 UI
3. Flux, Redux
---
#### 6. CSS:Inline Style
```jsx=
const imgUrl = 'https://imgur/react.png'
const divStyle = {
color: 'red',
backgroundImage: 'url(' + imgUrl + ')',
}
ReactDOM.render(
<div style={divStyle}>Hello World!</div>,
document.getElementById('app')
)
```
---
#### 6. CSS:Inline Style
1. 駝峰式命名
2. 物件型式
```jsx=
const divStyle = {
color: 'red',
margin: '2px',
paddingLeft: '.5rem',
backgroundColor: '#0f0',
}
```
```jsx=
ReactDOM.render(
<div style={{ color: '#f00' }}>Hello World!</div>,
document.getElementById('app')
)
```
---
## JSX 簡明入門教學指南
---
#### JSX 結構
JSX並非一種全新的語言,而是一種語法糖(Syntatic Sugar)。
```htmlmixed=
// HTML 寫法
<form class="messageBox">
<textarea></teextarea>
<button type="submit"></button>
</from>
```
有開始和關閉。
```jsx=
// JSX 寫法
<MessageBox />
<MessageBox>
```
---
#### JSX 表達式
```jsx
var text = 'Hello React';
<h1>{text}</h1>
<h1>{'text'}</h1>
```
---
#### React Component
```jsx=
class App extends React.Component {
render() {
const msg = 'Hello React!';
return (
<div>
<p>{msg}</p>
<MessageList>
</div>
);
}
}
```
---
#### 結合原生 JavaScript 語法
```jsx
// const 為常數
const lists = ['JavaScript', 'Java', 'Node', 'Python'];
class App extends React.Component {
render() {
return (
<ul>
{lists.map((result, index) => {
return (<li key={index}>{result}</li>);
})}
</ul>);
}
}
```
---
#### 註解
由於 JSX 最終會編譯成 JavaScript,註解也一樣使用 // 和 /**/ 當做註解方式
```jsx
// 單行註解
/*
多行註解
*/
var content = (
<List>
{/* 若是在子元件註解要加 {} */}
<Item
/* 多行
註解
喔 */
name={window.isLoggedIn ? window.name : ''} // 單行註解
/>
</List>
);
```
---
#### 屬性
在 JSX 中使用 `className` 和 `htmlFor` 替代。
```jsx
class App extends React.Component {
render() {
return (
<div className="message">
<p id="pHello">Hello React!</p>
<label htmlFor="pHello">Hi</label>
</div>
);
}
}
```
---
#### 屬性
Boolean 屬性
在 JSX 中預設只有屬性名稱但沒設值為 `true`,例如以下第一個 input 標籤 `disabled` 雖然沒設值,但結果和下面的 input 為相同:
```jsx
<input type="button" disabled />;
<input type="button" disabled={true} />;
```
反之,若是沒有屬性,則預設預設為 `false`:
```jsx
<input type="button" />;
<input type="button" disabled={false} />;
```
---
#### 樣式使用
在 JSX 中使用外觀樣式方法如下,第一個 {} 是 JSX 語法,第二個為 JavaScript 物件。與一般屬性值用 - 分隔不同,為駝峰式命名寫法:
```jsx
<div
style={{ color: '#FFFFFF', fontSize: '30px'}}
>
</div>
```
---
#### 事件處理
事件處理為前端開發的重頭戲,在 JSX 中透過 inline 事件的綁定來監聽並處理事件(注意也是駝峰式寫法)
```jsx
<HelloMessage onClick={this.onBtn} />
```
更多事件: [Supported Events](https://reactjs.org/docs/events.html#supported-events)
---
#### Props, State

---
#### Props, State

---
#### Props, State

---
## 讓我們回到程式
#### 小抄
1. 介紹 react es6 class
2. 利用 state.title 設定 h1 text
3. 利用 state.counter 設定 input value
4. 利用 inline style 設定 h1 color
5. 建立 button onClick alert
6. 利用 button onClick 改變 input value
7. 顯示計數器增減
8. 設定倒數計時器 10秒後 alert
9. 展示各種不同的事件處理方式
---
#### 題外插曲,改使用 SCSS
- 官方的 create-react-app 已經幫我們寫好 webpack 設定。
- 今天不管是用哪一套預處理,直接安裝 node-sass 就可。
- 可以混搭 scss, sass, less ... 任你用。
```shell=
yarn add node-sass -D
```
---
#### SCSS 基礎知識
- Variables 變數

---
#### SCSS 基礎知識
- Nesting 巢狀結構

---
#### SCSS 基礎知識
- Mixins

---
#### SCSS 基礎知識
- Inheritance 繼承

---
#### SCSS 基礎知識
- @import

```sass=
@import "base/head";
@import "base/body";
@import "base/foot";
```
---
#### SCSS 基礎知識
- 算數

---
#### 撰寫 Todo

---
#### Todo 步驟
1. 靜態 todo
2. 動態列表
3. 新增
4. 刪除
5. 勾選
6. 取得項目狀態
7. 編輯
---
#### 學習總整理
1. Functional Programming
2. Declarative
3. JSX
4. Components
5. state, props
6. Inline-style
7. scss
---

---

---
# END
{"metaMigratedAt":"2023-06-14T20:17:39.396Z","metaMigratedFrom":"YAML","title":"(H)尊絕不凡 React 教學","breaks":true,"contributors":"[{\"id\":\"36ba3409-97a0-4c0c-b357-4b738f6b17ad\",\"add\":23357,\"del\":4743}]"}