# [第03堂] React基礎知識
:::info
:bulb: **小複習:**
* **Node.js**:開源的 JavaScript 執行環境
* **NVM**:Node 的**版本**管理器
* **NPM**:Node 的**套件**管理器
* **NPX**:一樣是Node 的**套件**管理器,不過用完就會刪掉。
:::
## ES5/ES6
>ES的全名是ECMAScript,是一個由Ecma International訂定的腳本語言標準化規範,JavaScript就是根據這個規範去訂定的,[傳送門](https://medium.com/%E6%8B%89%E6%8B%89%E7%9A%84%E7%A8%8B%E5%BC%8F%E7%AD%86%E8%A8%98/%E8%A2%AB%E8%80%83%E5%80%92%E7%B3%BB%E5%88%97qq-es5-es6-es7-es8-es9-es10-c3dab7653373)
### ES5
* 嚴格模式
* Array/Object操作的方法
* Array.find
* Array.filter
* Array.map
* ...
### ES6
* **let & const**
* let可變動
* const不可變動,宣告時要給定initialize
```javascript==
//let
let a;
a=10;
console.log(a);
a=20;
console.log(a);
//const
const b=100;
console.log(b);
//下面可以拿掉註解測試看看
//b=200;
//console.log(b);
```
* **箭頭函式 Arrow Functions**
```javascript==
//不帶參數
//ES5
function func_name(){
console.log('Hello World!');
}
//ES6
func_name = () =>{
console.log('Hello World!');
}
//帶一個參數
//ES5
function func_name(e){
console.log(e);
}
//ES6
func_name = e =>{
console.log(e);
}
//帶兩個(含)以上參數
//ES5
function func_name(e,i){
console.log(e,i);
}
//ES6
func_name = (e,i) =>{
console.log(e,i);
}
//關於return
func_name = () => something
func_name = () =>{
return something;
}
```
* **參數預設 Default Parameters**
傳入function的參數沒有給定值時,會出現Exception,最快的解決方法就是給定預設值,在ES6中給定預設值的方式更為快速簡單
```javascript==
BMI=(height=1.75, weight=65) => {
let BMI=weight/(height^2);
console.log(BMI);
}
```
* **文字模板 Template Literals**
```javascript==
// ES5
var name='Jack';
var start = 'Hello'+name+'!';
//ES6
const name='Jack'
const start = `Hello ${name}!`
```
* **多行字串輸入 Multi-line Strings**
```javascript==
// ES5
var fruit =
'apple,' +
'banana'
//ES6
const fruit =
`apple,
banana`
```
* **解構賦值 Destructuring Assignment**
```javascript==
const Jack={age:40,gender:'male'};
//一般
console.log(Jack.age,Jack.gender);
//解構
const {age,gender}=Jack;
console.log(age,gender);
//賦值
const Jack {age:x} = {age:40}; //x=40
const {age:x} = Jack; //x=40
```
* **物件實字 Enhanced Object Literals**
假如object內的元素其key與value名稱一樣,可以省略key直接寫 value 名稱即可。
```javascript==
// ES5
var name = 'Jack';
var obj = {
name: name
};
// ES6
const name = 'Jack';
const obj = { name };
```
## JSX
> **JavaScript XML,JavaScript 的語法擴充,屬性名稱以小駝峰方式撰寫,要比較留意的是最外層只能有一個根元素。**
下面的標籤語法不是一個字串也不是HTML,而是把右邊的HTML當成一個物件存到變數中,這種把HTML寫在JavaScript的程式碼中的技術,我們稱之JSX。
```javascript===
const element = <h1> 你好,世界!</h1>;
```
可以在HTML標籤中利用「{}」寫JavaScript表示式。
```javascript=
const showOne = true;
const element = <h1>{showOne?1:0}</h1>
```
或是將style變為一物件、屬性名稱規則改用駝峰法(用大寫區隔)、屬性的值變成字串。
```javascript=
const styleArgument={ fontSize: '100px', color: 'red' };
ReactDOM.render(
<h1 style={ styleArgument }> Hello, world! </h1>,
document.getElementById('root')
);
```
在JSX中的HTML標籤屬性基本上都與原本的HTML標籤屬性相同,比較特別的是class和for是js的保留字,因此這兩個屬性在JSX需要寫成**className**和**htmlFor**。
```javascript=
<div className="title">標題</div>
```
因為JSX 並不是單純的 JS ,所以是沒辦法直接被套用在網頁上的,這時候就必須要透過 babel 進行轉譯並搭配 Webpack 進行打包的動作。
而透過babel進行轉役會變成怎麼樣子呢?
```javascript=
<a href="https://facebook.github.io/react/">Hello!</a>
```
例如上面的Hello world! 透過 babel 編譯後會轉成下面 React library 的 React.createElement() function calls。
```javascript=
// React.createElement(元件/HTML標籤, 元件屬性,以物件表示, 子元件)
React.createElement('a', {href: 'https://facebook.github.io/react/'}, 'Hello!')
```
:::info
:bulb: 不過 React 並不要求使用 JSX,只是與createElement相比,JSX可閱讀性比較高。
:::
**下面會簡單介紹一些JSX的寫法**
* **變數**:用 {} 包起來
```javascript=
const name = 'Andy'
const htmlA = <h1>Hello {name}<h1>
const htmlB = <h1>`Hello ${name}`<h1>
```
* **多行的 HTML**:最外層多加一個 ()
```javascript=
const html = (
<div>
<span>Hello Andy</span>
</div>
)
```
* **if**:改寫成三元運算子
{ } 中只能放 JavaScript expression,而if 是一個 JavaScript statement,所以在 JSX 無法使用 if。
```javascript=
const showOne=true;
const element = <h1>{showOne?1:0}</h1>
```
* **html標籤中的數字**:
如果值是數字,JSX 會幫你加上 "px" 單位,若不想用 px 就得明確指定單位。
```javascript=
// 值同 10px
<div style={{ height: 10 }}>
Hello World!
</div>
```
:::info
:bulb: 小練習
* 寫一個有底色、寬100%、高50px的div (用inline style)
* 宣告 a = Hello
* 在div中顯示Hello world (Hello必須是變數a)
:::
## Scss
> **現今主流的CSS預處理器之一**
* **巢狀結構**
```javascript==
#banner{
...
#logo{ // 等同於 #banner #logo
...
img{ // 等同於 #banner #logo img
...
}
}
nav{ //等同於 #banner nav
...
}
}
```
* **&連接**
```javascript==
a{
color:red;
&:hover{ //等同於 a:hover
color:red;
}
&:active{ //等同於 a:active
color:blue;
}
}
```
:::info
:bulb: 小練習
* 將css改用引入css檔案的方式撰寫

:::
## Components
> 我們稱之元件,Component 的字首須為大寫字母
React 提供了兩種元件實做方式,分別為Class & Functional,
### Class Component
> 使用 Class(類別) 建立的元件,具有生命週期,具有State,擁有this,需要引入React Component,一定要實作render。
```javascript=
import React, { Component } from "react";
export default class Button extends Component { //用extends去繼承Component
constructor(props) {
super(props),
}
const handleButtonClick =()=>{
console.log('click');
}
render() { //用render()函式去收集要渲染到畫面上的東西(放在return值),再去改變DOM
return <button onClick={this.handleButtonClick}>btn</button>;
}
}
```
### Functional Component
> 使用 Function(函式) 建立的元件,沒有生命週期,沒有State,編譯更快(因為不用將class轉換成es5)
```javascript=
function Button(props) {
const handleButtonClick =()=>{
console.log('click');
}
return <button onClick={handleButtonClick}>btn</button>;
}
```
不過在Hook出現後Functional Component 也具有生命週期以及State。
:::info
:bulb: Hook
在 React 16.8 引入的一種特性,可以在函數式組件中使用 React 功能的 API。以前如果想在元件中使用生命週期、State 等,一定要使用 Class 元件,直到 Hook 出現後,不使用 Class 的情況下也能具有生命週期以及State。
:::
### Props & State
>React 中 Component 只能透過資料狀態的改變來更新 UI,而 React 元件有兩種資料來源:
>* 透過外部傳進來元件的 Props
>* 元件內部自己維護的 State
#### props
>properties的縮寫,屬性。
>用於元件與元件間傳遞資料,是靜態(唯讀)的。
#### state
>內部狀態
>元件存放資料的地方,以物件的方式存放(key:value),需要在constructor建立自身state,並且利用setState去改變state的值。
```javascript=
// Class寫法
constructor(props) {
super(props);
// 建立state並給予初始值
this.state = {
currentPage: 'one',
}
}
// 利用this.setState 改變state的值
this.setState({
currentPage:'two',
})
// Hook寫法
const [page,usePage] = useState("one");
usePage("two");
```
constructor 是在 Component 建立的時候自動執行的 function,所以如果沒有要做任何事情的時候,可以不用寫 constructor。但如果有這個需求,記得要把寫好寫滿 constructor(props) 、 super(props) 這樣才可以確保東西都有初始化好。
## this
> 在 React 類組件中的 this 通常指向該類的實例,即指向當前元件的實例。
這意味著可以通過 this 訪問該組件的狀態(state)和屬性(props),以及元件的方法,ex:可以使用 this.setState() 來更新組件的狀態,以及訪問 this.props 來獲取父組件傳遞的屬性。
## setState
>可以透過this.setState()修改State。
只需要傳入想要更新的 key-value pairs ,React 會自動將傳入和當前State的 key-value pairs 合併 (merge),把新的 key-value paris 會取代掉舊值。
```javascript=
this.setState({ name: "cherry" })
```
state 的更新是非同步的,因此執行完 setState() 更新 state 後,接著下一行 code,馬上存取 this.state 不一定會拿到最新的值。
setState 還有一個 optional 的第二個參數 callback,callback 是一個 function,用途是當 state 確定已經被更新後,React 就會 call 這個 callback function,讓你可以在 callback 中做些你需要確定 state 已經被更新後才能做的事。
```javascript=
setState(stateChange, callback)
// 舉個例子
const changeInput = (event) => {
// 會先將值存到text中,再執行後面的validateInput function
this.setState({ text: event.target.value }, () => {
this.validateInput();
});
}
const validateInput = () => {
if (this.state.text.length === 0) {
this.setState({ inputError: 'Input cannot be blank' });
}
}
```
而setState 也可以接受一個 function 當作參數,該 function 的參數 prevState 是當前最新的 state,而參數 props 是元件當前的 props,在 function 返回一個你要更新的 state 。
```javascript=
// 錯誤寫法
this.setState({
counter: this.state.counter + this.props.increment,
});
// 正確寫法
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
```