# 從 Hooks 開始,讓你的網頁 React 起來系列的閱讀筆記(1-6)
###### tags: `閱讀筆記` `前端筆記` `React`
## 完成章節
- 1 - 6(2021/11/22)
## React 支援 JSX
### JSX 是什麼呢?
JSX 是 JavaScript XML,雖然看起來很像 HTML 但是它並不全然是 HTML。
JSX 可以很方便地創造 React Element。
[*ref.:React JSX*](https://www.w3schools.com/react/react_jsx.asp)
```javascript=
// 使用 JSX
const myelement = <h1>I Love JSX!</h1>;
ReactDOM.render(myelement, document.getElementById('root'));
// 不使用 JSX
const myelement = React.createElement('h1', {}, 'I do not use JSX!');
ReactDOM.render(myelement, document.getElementById('root'));
```
### 為什麼在寫 React 的時候推薦使用 JSX?
因為在 React 的世界中所有的東西都是一個元件(Component)。每一個 Component 就是代表一個頁面的區塊。

[*ref.: Full React Tutorial #3 - Components & Templates*](https://www.youtube.com/watch?v=9D1x7-2FmTA&list=PL4cUxeGkcC9gZD-Tvwfod2gaISzfRiP9d&index=3)
如上圖顯示,一個 Component 就是一個區塊(e.g. Navbar, Blog Text and Sidebar)
使用 JSX 可以幫助我們建立含 JavaScript 邏輯的 Component。(這點就像是之前上 Udemy 教的 EJS,就是可以直接在要渲染在 DOM 裡面的 HTML 寫 JavaScript,達到動態顯示不同的效果)(e.g. 使用者點擊登入後原本登入鍵就會變成登出鍵)。
### 簡單的 JSX 應用
要記得 `return` JSX(也就是類似 HTML 的東西),背後會經過轉譯變成瀏覽器懂的 JavaScritp。
**需要注意不像 HTML ,如果 JSX 要使用 CSS class 要用 className,因為 class 在 JavaScript 是關鍵字不能使用。**
```htmlembedded=
<div id="root"></div>
```
```javascript=
function MyName () {
const myName = 'Lun';
return (
<p className="text-red">我的名字是 {myName}。</p>
)
}
ReactDOM.render(<MyName />, document.querySelector('#root'));
```

*打開 Dev Tool 會發現已經被轉成一般的 HTML 以及 class*
#### 可以直接寫 inline-style
可以宣告一個 inline-style 的物件,之後像一般的 HTML 一樣寫在標籤裡。
```javascript=
function MyName () {
const textRed = {
color: 'red'
};
const myName = 'Lun';
return (
<p style={textRed}>我的名字是 {myName}。</p>
)
}
ReactDOM.render(<MyName />, document.querySelector('#root'));
```
也可以**直接**寫在 style 裡面,但是記得要用兩個 `{{}}`。
```javascript=
function MyName () {
const myName = 'Lun';
return (
<p style={{
color: 'red'
}}
>我的名字是 {myName}。</p>
)
}
ReactDOM.render(<MyName />, document.querySelector('#root'));
```
#### 既然支援 JavaScript,當然也可以使用陣列方法
目前先不要省略 `return`,熟悉了再省略。而且如果使用到變數的東西都要使用 `{}` 包起來。(e.g. {manga.map(....)})
```javascript=
function List () {
const manga = ['異獸魔都', '進擊的巨人', '請叫我英雄'];
return (
<ul>
{manga.map(value => {
return(<li>{value}</li>);
})}
</ul>
);
}
ReactDOM.render(<List />, document.querySelector('#root'));
```

## 基本 useState 的運用
重點關鍵字:
> 這個方法之所以叫做 useState 是因為在 React 組件中,這些會連動導致畫面改變的「資料(data)」習慣上被稱作「狀態(state)」。以紅綠燈來說,假設有一個資料可以用來表示紅綠燈的顏色,0 是紅燈、1 是綠燈,當這個資料是 0 的時候,燈號就會變成紅燈的「狀態」;當資料變成 1 時,燈號就會變成「綠燈」的狀態。
> [*ref.:[Day 06 - 計數器] 醒醒啊!為什麼一動也不動 - useState 的基本使用*](https://ithelp.ithome.com.tw/articles/10219287)
==之後看到狀態(state)就可以想成是資料(data)理解。==
**在第六篇中學習到使用 React 時如果想要把更新的資料渲染在頁面上就要使用 useState。**
用 Vanilla JS 的話就像之前寫的方式一樣,就不再贅述。[Vanilla JS 計數器](https://codepen.io/lun0223/pen/YzxMLoe)
新奇的地方是用 useState。useState 的名稱有 `use`,有 `use` 開頭的方法就代表它是一個 `Hook`。此外也有 `state(狀態)`代表這個方法有涉及到資料(data)相關的事情。
如果沒有使用 `useState`,那資料(data)(也就是狀態)有更新的話 React 本身並不會知道,所以即使值改變,但是畫面不會變。
```javascript=
const Content = () => {
let count = 256;
function add () {
count ++;
console.log(count);
}
return (
<div className="container">
{console.log('RENDER!')}
<div
className="chevron chevron-up"
onClick={add}
/>
<div className="number">{count}</div>
<div
className="chevron chevron-down"
/>
</div>
)
};
ReactDOM.render(<Content />, document.querySelector('#root'));
```

*即便 `count` 的值有更新,但是 React 並不會知道這個值改變了,所以不會更新畫面(而且只會 render 一次)*
此時使用 useState 方法,React 就會知道值改變了,並且會渲染頁面。
**`useState` 回傳的函式通常會以 `setXXX => XXX 為基準值的代號,比方來說 count,所以函式就是 setCount` 提高程式碼閱讀性。**
使用步驟:
1. 先解構方法(取出)
2. 再用陣列結構提高使用的方便性
3. `useState(256)` 代表起始值(count)為 256
4. 之後在 `add` 函式中叫用並傳入 Arguments `setCount(count + 1)`
5. 事件(`onClick`)觸發函式,執行任務
```javascript=
// 1. 解構取出該方法
const { useState } = React;
const Content = () => {
// 2. 陣列結構取出叫用 useState 後得到的值
const [count, setCount] = useState(256);
function add () {
// 3. 叫用叫用 useState 後得到的函式並傳入 Argument(藉由陣列解構所以 setCount 會指向該函式的記憶體所以我可以叫用)
setCount(count + 1);
}
function minus () {
setCount(count - 1);
}
return (
<div className="container">
{console.log('RENDER!')}
<div
className="chevron chevron-up"
onClick={add}
/>
<div className="number">{count}</div>
<div
className="chevron chevron-down"
onClick={minus}
/>
</div>
)
};
ReactDOM.render(<Content />, document.querySelector('#root'));
```

*這樣子當狀態(state)有更動,React 也會知道,所以就會渲染畫面(狀態改變就會 `console.log('RENDER!')`)*
### 為什麼要陣列結構?
增加使用時的便利性及程式碼閱讀性,因為 `useState()` 被叫用後就會回傳一個陣列,第一個值代表基準值,第二個值是一個函式,會以基準值來執行觸發事件要做什麼以及背後會自動觸發 re-render。
如果不用陣列結構的話就會有點麻煩:
```javascript=
const { useState } = React;
const Content = () => {
const counting = useState(256);
console.log(counting); // (2) [256, ƒ] f 代表函式
const count = counting[0]; // 就要很土法煉鋼地用 indexNum
const setCount = counting[1];
function add () {
setCount(count + 1);
}
function minus () {
setCount(count - 1);
}
return (
<div className="container">
{console.log('RENDER!')}
<div
className="chevron chevron-up"
onClick={add}
/>
<div className="number">{count}</div>
<div
className="chevron chevron-down"
onClick={minus}
/>
</div>
)
};
ReactDOM.render(<Content />, document.querySelector('#root'));
```
### 為什麼用 `const [count, setCount] = useState(256)` 時可以更改常數 `count`?
一開始我用 `setCount(count ++)` 竟然報錯。
```javascript=
const { useState } = React;
const Content = () => {
const [count, setCount] = useState(256);
function add () {
// 看範例使用 +1 就想說用 ++ 應該沒差
setCount(count ++);
}
function minus () {
setCount(count - 1);
}
return (
<div className="container">
{console.log('RENDER!')}
<div
className="chevron chevron-up"
onClick={add}
/>
<div className="number">{count}</div>
<div
className="chevron chevron-down"
onClick={minus}
/>
</div>
)
};
ReactDOM.render(<Content />, document.querySelector('#root'));
```

*結果報錯了,因為陣列結構後 `count` 確實是由 `const` 宣告的常數,因為 `count ++` 代表的是 `count = count + 1` 但因為值(256)是基本型別(primitive type)所以是不能改變的(immutable)*
**但是為什麼畫面還會改變啊囧!!!!!**
一開始我也是想不透為什麼,後來在網路上找到有大神解釋背後的概念:
[*ref.:Why React Hook useState uses const and not let*](https://stackoverflow.com/questions/58860021/why-react-hook-usestate-uses-const-and-not-let)
>Not really. When the component is rerendered, the function is executed again, creating a new scope, creating a new count variable, which has nothing to do with the previous variable.
>Note: Hooks are way more sophisticated and are not actually implemented like this. This is just to demonstrate a similar behavior.
```javascript=
let _state;
let _initialized = false;
function useState(initialValue) {
if (!_initialized) {
_state = initialValue;
_initialized = true;
}
return [_state, v => _state = v];
}
function Component() {
const [count, setCount] = useState(0);
console.log(count);
setCount(count + 1);
}
Component();
Component(); // in reality `setCount` somehow triggers a rerender, calling Component again
Component(); // another rerender
```
看了大神的分享仔細思考其概念:
1. 初始化後就不會再初始化了(也就是 initialValue = _state)
2. useState() 回傳陣列中的第二個值(也就是函式)其實是改變外層變數的值,也剛好陣列中第一個值的記憶體是指向外層變數
3. 但是外層變數是 `let` 宣告的,所以同個變數名稱可以重新和值的記憶體連結,不過 `const` 指向的其實是外層變數的上一個值的記憶體,不過我們沒有使用同個變數名稱,所以不會錯
4. 然後當第二個函式被叫用的時候又會觸發 render,所以就會創造新的範疇
**實際操作**
除了第一次 Component Render 外,當事件觸發 `setCount(count + 1)` 時確實又 re-render Component 了。不過這時候又發現僅管我 `console.log(count)` 寫再後面,但是 `setCount(count + 1)` 會比較晚執行(雖然我目前還不知道為什麼,但是至少知道背後一部份的原理),之後說不定就會明白了。
```javascript=
// 1. 解構取出該方法
const { useState } = React;
const Content = () => {
const [count, setCount] = useState(256);
function add () {
setCount(count + 1);
console.log(count);
}
function minus () {
setCount(count - 1);
}
return (
<div className="container">
{console.log('RENDER!')}
<div
className="chevron chevron-up"
onClick={add}
/>
<div className="number">{count}</div>
<div
className="chevron chevron-down"
onClick={minus}
/>
</div>
)
};
ReactDOM.render(<Content />, document.querySelector('#root'));
```

### 聰明的 React 也只會更新必要的 Element
React 背後有超猛函式確認更新的 Element 並只更新它,可以有效降低效能(好厲害!)
[*ref.:React 只更新必要的 Element*](https://zh-hant.reactjs.org/docs/rendering-elements.html#react-only-updates-whats-necessary)

## 參考資料
1. [從 Hooks 開始,讓你的網頁 React 起來 1 - 6](https://ithelp.ithome.com.tw/users/20103315/ironman/2668)
2. [使用 State Hook](https://zh-hant.reactjs.org/docs/hooks-state.html)
3. [Learn useState In 15 Minutes - React Hooks Explained](https://www.youtube.com/watch?v=O6P86uwfdR0&t=834s)
4. [Full React Tutorial #8 - Using State (useState hook)](https://www.youtube.com/watch?v=4pO-HcG2igk)
5. [React JSX](https://www.w3schools.com/react/react_jsx.asp)