---
# System prepended metadata

title: React

---


{%hackmd lTq14m8-RK6cksBvQ0Rnrg %}

# React

React是一個自由及開放原始碼的前端JavaScript工具庫， 用於基於UI組件構建使用者介面。 它由Meta和由個人開發者和公司組成的社群維護。

## Components

Components可區分為兩大類型：Function Components vs Class Components

### Function Components


### Class Components


## Virtual DOM

### 什麼是Virtual DOM
React為了解決MVC、MVP、MVVM等架構的問題。以「當 Model 發生改變時直接重新渲染 View」的方式，引入 Virtual DOM 的概念。透過 JavaScript 物件來描述 DOM 結構，產生當下 Model 對應的 Virtual DOM 結構，再和上次的 Virtual DOM 結構透過 Diff 演算法比較，再將兩者差異建立在真實 DOM 上。
![ApLV4M6](https://hackmd.io/_uploads/Hka1slJ86.png)
參考資料: [Virtual-DOM-的起源](https://hackmd.io/@Heidi-Liu/virtual-dom#%E8%A3%9C%E5%85%85%EF%BC%9AVirtual-DOM-%E7%9A%84%E8%B5%B7%E6%BA%90)

### Virtual DOM的流程
1. 初次使用setState()方法的時候，React會先複製一份dom的物件（即為Virtual DOM
2. 當React component的state改變時，會比對先前的Virtual DOM和當前的 Virtual DOM差異，稱之為**diff運算**
3. Virtual DOM先用自己的演算法(diff)算出實際需要更新的部分，比對兩者差異之後，再去更動真實的DOM，有效減少渲染的次數 ，提高效能

這是一般的html結構
```htmlembedded
<div id="header">  
    <h1 class="title">Apple</h1>
    <p class="content">lemon</p> 
</div>
```
這是Virtual DOM的結構，是JavaScript模擬出來的物件， 會以以下的格式儲存起來
```json
{
    tag: "div",
    props: {
        id: "header"
    },
    children: [
        {
            tag: "h1",
            props: { className: "title" },
            children: ["Apple"]
        }, {
            tag: "p",
            props: { className: "content" },
            children: ["lemon"]
        }
    ]
}
```
* type: DOM標籤名稱
* props:DOM屬性
* children:DOM子元素

下方就用程式碼來稍微模擬一下Virtual DOM的執行過程
1. createELement :先使用Virtual DOM提供的createELement方法來生成真實的DOM
```javascript
var count = 0;    

var tree = render(count);               
var rootNode = createElement(tree);     
document.body.appendChild(rootNode);
```
2. 當count變動時 Virtual DOM進行比對 再將差異patch到實際的DOM
```javascript
count++
var newTree = render(count);
var patches = diff(tree, newTree);
rootNode = patch(rootNode, patches);
tree = newTree;
```

**ReactElement**
```javascript
const element = <h1 id="hello">Hello, world</h1>
```
上面的代碼經過編譯後其實生成的代碼是這樣的：
```javascript
React.createElement("h1", {
  id: "hello"
}, "Hello, world");
```
執行 React.createElement 函數，會返回類似於下面的一個 js 對象，這個對象就是我們所說的 React 元素：
```javascript
const element = {
  type: 'h1',
  props: {
    id: 'hello',
    children: 'hello world'
  }
}
```
React 元素也可以是用戶自定義的組件：
```javascript
function Button(props) {
  return <button style={{ color }}>{props.children}</button>;
}

const buttonComp = <Button color="red">點擊我</Button>
```

#### 什麼是patch？patch指的是在原有的DOM結構上做異動
**關於diff演算法**
Virtual DOM的diff演算法為O(n) 與傳統的差異在於下幾點：

1. Virtual DOM只會比較同一層級的節點
2. 同一層的節點為了識別個別具有唯一的key，為了避免節點只是移動又被重新創建一次
3. 如果發現節點不見了其子節點也會一併刪除，不會做進一步的比對

以往如果是手動操作，每操作一次就會更新一次DOM，如果是透過react setState就會是將多個操作合併為一次的操作，避免頻繁更新頁面，因此開發者只要專注在資料邏輯上，畫面的更新機制全部交給React處理即可。
![image](https://hackmd.io/_uploads/BJAyMZkIT.png)

參考資料:
[理解React Virtual DOM](https://medium.com/coding-hot-pot/react-vitural-dom-134fa79e0d4f)
[你不知道的 React Virtual DOM](https://www.readfog.com/a/1641376221189214208)

## 傳值

@StanShih 

React屬於單向資料流，所有的資料都是從父層往子層傳遞
React的畫面是由許多元件組合建構而成，因此元件算是React的核心靈魂

![image](https://hackmd.io/_uploads/rk_0Kl1L6.png)

### 父傳子 Props

```javascript=
import React, { Component } from 'react';
import './App.css';
import Person from './Person/Person';

class App extends Component {
  render() {
    return (
      <div className="App">
        <h1>Hello World! React</h1>
        <Person name="Andy" age="21"/>
        <Person name="Jack" age="22"/>
      </div>

    );
  }
}

export default App;
```

```javascript=
import React from 'react';

const person =(props)=>{
  return <p> I'm {props.name} and I'am {props.age} yesrs old.</p>
}

export default person;
```

### 子傳父 

#### callback


#### 

## JSX

JSX 是 JavaScript 的語法擴展，它允許你以類似 HTML 的語法來描述你的 UI。JSX 的好處在於除了需遵守三個 JSX 規則之外，你無需學習 HTML 和 JavaScript 之外的任何新符號或語法。
JSX 是一種似 HTML 結構並混合 JavaScript 語法功能的語法糖（Syntatic Sugar），背後其實封裝了 React Raw API，但相較於 React Raw API，更加簡潔與直觀，並帶有明顯的 UI 結構，因此更好閱讀與理解。一眼就能理解為什麼寫 React 時，通常都是直接用 JSX 語法，而非使用 createElement。不過，依然必須要清楚 JSX 僅是一種 React 提供的語法糖 ，並且「不能」被瀏覽器直接理解。。

JSX 規則

> 1. 返回單一根元素
> 若要從元件傳回多個元素，請使用單一父標籤包裝它們。
> 2. 關閉所有標籤
> JSX 要求標籤明確關閉：自關閉標籤（如`<img>`必須成為`<img />`）和包裝標籤（如
> `<li>oranges`必須寫為`<li>oranges</li>`。
> 3. 大多數東西都採用駝峰命名法！
> JSX 變成 JavaScript，用 JSX 寫的屬性成為 JavaScript 物件的鍵。在您自己的元件中，您經常希望將這些屬性讀入變數中。但 JavaScript 對變數名稱有限制。例如，它們的名稱不能包含破折號或保留字，例如class.
> 
> 這就是為什麼在 React 中，許多 HTML 和 SVG 屬性都是用駝峰命名法編寫的。例如，stroke-width您可以使用strokeWidth. 因為class是一個保留字，在 React 中你可以這樣寫，以對應的 DOM 屬性className命名：


需注意的是，瀏覽器無法直接理解 JSX，因此你需要一個 JavaScript 編譯器，例如 Babel，將你的 JSX 語法轉換為常規 JavaScript。

同樣地將一樣的 Hello World !
![image](https://hackmd.io/_uploads/rymYebkI6.png)
![image](https://hackmd.io/_uploads/HkYqxWkLp.png)
![image](https://hackmd.io/_uploads/HJgTlZkUT.png)
![image](https://hackmd.io/_uploads/HksLbb1IT.png)



## 生命週期（Lifecycle）

**1. Mounting（掛載）：**
* constructor(): 在組件被創建時調用，用於初始化狀態。
* static getDerivedStateFromProps(): 在組件被創建和每次接收新的props時都會調用，用於更新狀態。
* render(): 根據組件的狀態和屬性生成虛擬DOM。
* componentDidMount(): 在組件被插入DOM後調用，通常用於執行一次性的資源請求或設定訂閱。

**2. Updating（更新）：**
* static getDerivedStateFromProps(): 同樣在更新階段調用。
* shouldComponentUpdate(): 在更新前調用，返回false可以阻止組件的重新渲染。
* render(): 更新虛擬DOM。
* getSnapshotBeforeUpdate(): 在實際DOM更新之前獲取一些信息，通常用於捕獲滾動位置等。
* componentDidUpdate(): 在組件完成更新後調用，通常用於執行一些額外的操作，比如狀態的同步。

**3. Unmounting（卸載）：**
* componentWillUnmount(): 在組件即將從DOM中卸載時調用，通常用於清理計時器、取消綁定等資源回收操作。

### useEffect

React Hooks 中的一個關鍵函數，用於處理副作用（side effects）的邏輯。副作用通常包括資料的獲取、訂閱事件、手動操作DOM等，而這些操作可能會影響組件的狀態和渲染。






## Hook?
在 React 16.8 之前，如果我們想要使用到生命週期的方法或狀態 (state)，那我們只能使用 React 的 class component。但 React hooks 的出現，讓我們即使使用 functional component，也能夠使用到 React 的功能和狀態。在 React 中，用 `use` 開頭的函式我們會把它稱之為 Hook，有些 Hooks 是 React 內建的功能，例如：`useEffect`，但我們也可以創造自己的 Hooks。Hooks 相較於函式更嚴謹、有一些需要遵守的規範，我們接下來在下方會提到。

### Hook 解決了什麼問題?
React 團隊開發 Hooks 主要為了解決這三個原因

#### 狀態相關的邏輯 (stateful logics) 在 class component 之間難以複用
在使用 class component 時，React 並沒有提供可以將重複的邏輯添加到元件的方法。因此，開發者可能使用 `render props` 或是 `higher-order components` 的方式達到，但這個缺點會是需要重新架構元件，不僅麻煩、而且程式碼也不易讀 (React 文件戲稱為 wrapper hell)。因此， Hook 的解決的主要問題之一，正是讓共享狀態邏輯。

使用 Hooks，開發者可以從元件中提取狀態相關的邏輯，並對它進行獨立複用。我們也不需要重組元件，就可以在元件中複用相同邏輯。舉例來說，如果某個應用程式需要偵測頁面滑動，並根據滑動來觸發某些函式，這時我們可以寫一個 `useScroll`，並在不同頁面共享這個 `useScroll` 的狀態邏輯。目前在 React 的社群中，有很多 Hooks 的函式庫，便提供了各式各樣可重複使用的 Hooks。

#### 在 Hooks 出現前，複雜元件的邏輯會越寫越讓人難理解

當 class component 越來越龐大或邏輯複雜時，我們可能會在同一個生命週期方法內需要加入很多不相關的邏輯，例如：`componentDidMount` 要處理 data fetching 和事件偵聽器邏輯，不僅難以理解也不好維護，且在很多情況下，也無法把這些元件拆成更小的元件。

為了解決此問題， Hooks 允許將一個元件拆為更小的函式，而不是根據生命週期的方法拆分，例如上段例子，data fetching 和 事件偵聽器兩種邏輯，可以在同一個元件，通過兩個 `useEffect` 各自處理，又或者兩者拆成兩個 custom hooks。透過這樣細分，不相關的邏輯可以拆到不同的 `useEffect`，讓副作用的邏輯更好管理。

#### class 對於開發者來說不好理解

React 團隊發現，class 可能會是學習 React 的主要障礙。因為 class 的概念在 JavaScript 和其他語言中相當不同 (在 JavaScript 當中，class 是語法糖)，如果開發者過去是寫其他語言，轉來寫 JavaScript 時，需要特別了解 class 在 JavaScript 是如何運作的。

為了解決這些問題，Hooks 可以在沒有 class 的情況下使用更多 React 的特性。從概念上講，React 元件一直更接近函式。 Hooks 包含函式，但不犧牲 React 的實用精神，且不需要特別學習複雜的 functional or reactive programming。

## Functional Components vs Class Components:
![image](https://hackmd.io/_uploads/S1snTe1U6.png)



