# React 概述 <center><img src="https://miro.medium.com/v2/resize:fit:1400/0*y6IcBe5J1AdALzXw.png" /></center> ## 前言 在我們今天的主角 React 登場之前,我們先來聊聊一個更根本的概念:「什麼是前端框架?」 在網頁開發的早期,我們就是用這三樣東西「純手工」打造網頁。 * 用 HTML 刻出骨架。 * 用 CSS 加上美觀的樣式。 * 用 JavaScript (我們常說的 Vanilla JS) 來增加互動,像是「點擊按鈕後,跳出一個視窗」。 這在製作簡單的靜態網站時,完全沒問題。 但是,當網頁應用 (Web App) 變得越來越複雜——想想看 Gmail、Google Maps 或是 Facebook,我們開始開發這類網站時將會遇到巨大的麻煩。 想像一下,你正在用純 JavaScript 開發一個像 Facebook 這樣的動態牆: * 有幾十個「讚」按鈕,每個都要獨立計數。 * 有人留言,列表要「即時」更新,不用重新整理頁面。 * 右上角的「通知」圖示要顯示未讀訊息的「紅點」。 ![image](https://hackmd.io/_uploads/HJY1N5y1Ze.png)![image](https://hackmd.io/_uploads/ryFWVqykWg.png)![image](https://hackmd.io/_uploads/ByQlE51yZx.png) 如果你真的利用純 JavaScript 去開發邏輯部分的話,你很快就會發現,你的 JavaScript 程式碼變得一團混亂: * DOM 操作地獄: 你會寫滿 <code>document.getElementById</code> 和 <code>.addEventListener</code>。 * 狀態管理混亂: 你的資料(例如:按讚數、留言列表)散落在各處。當資料更新時,你必須「手動」記得去更新畫面上 所有 相關的地方。 * 難以維護: 程式碼牽一髮動全身,修改一個小功能,可能導致另一個地方壞掉。 **而以上就是「前端框架」誕生的原因。** 前端框架幫我們**能夠更有結構化、更方便的去開發網站**。 主流的前端框架有分很多種像是 React、Vue、Angular 等等,那麼我們這次的主角就是 **React**。 ## 核心概念 (一) - 元件化 (Component-based) ### 甚麼是元件 (Component) 就像是你玩樂高積木一樣,能夠把複雜的 UI 變成一個可以重複使用的積木。例如: <code>NavBar</code>、<code>Card</code>、<code>Button</code>。 ### JSX 語法擴充 - 寫在 JavaScript 中的「HTML」 傳統的 HTML 與 Javascript 是不能夠寫在一起的,所以每次當你要去操作網頁中的某個物件的時候,每次都要手動操作 DOM (<code>document.getElementById...</code>),如果你做的網頁很大,那麼這會變得非常的麻煩。所以有了 JSX,我們網頁的 UI 結構和邏輯(例如 map 產生列表)可以寫在一起,非常直觀。 ### Function Component (函數式元件) **Function Component 就是一個普通的 JavaScript 函式 (Function)。** 它接受一個名為 `props` (屬性) 的物件作為參數,然後**回傳 (return)** 描述你想在螢幕上看到什麼的 **React 元素 (通常是 JSX)**。 ### Props (屬性):元件間的溝通 * 概念: 父母 (Parent Component) 傳遞資料給小孩 (Child Component) 的方式。 * 特性: 單向資料流 (One-Way Data Flow)、唯讀 (Read-Only)。 * 範例: 定義一個 <code>Button</code> 組件, 假設<code><Button text="點我" color="blue" /></code>,那麼其中 <code>text</code> 與 <code>color</code> 為 <code>Button</code> 這個元件的 Props ### 範例 - 介紹卡片 (虛擬碼) #### 不使用 React ```html= <body> <h1>我們的團隊</h1> <div class="card"> <img src="https://via.placeholder.com/150" alt="用戶頭像"> <h3>Alice</h3> <p>我是一個前端工程師。</p> </div> <div class="card"> <img src="https://via.placeholder.com/150" alt="用戶頭像"> <h3>Bob</h3> <p>我是一個後端工程師。</p> </div> <div class="card"> <img src="https://via.placeholder.com/150" alt="用戶頭像"> <h3>Stacy</h3> <p>我是一個 PM。</p> </div> </body> ``` #### 使用 React <code>ProfileCard.js</code> ```javascript= import React from 'react'; // 這就是一個「元件」 // 它是一個函式,會接收一個 props 物件 (裡面放著外面傳進來的資料) // 然後回傳它該長什麼樣子的 JSX function ProfileCard(props) { return ( <div className="card"> <img src={props.imageUrl} alt="用戶頭像" /> <h3>{props.name}</h3> <p>{props.description}</p> </div> ); } export default ProfileCard; ``` <code>App.js</code> ```javascript= import React from 'react'; import ProfileCard from './ProfileCard'; // 載入我們剛剛做的卡片元件 import './styles.css'; // 假設 CSS 樣式跟 HTML 範例一樣 // 這是主要的 App 元件 function App() { const profileData = [ { name: "Alice", description:"我是一個前端工程師", imageUrl: "https://via.placeholder.com/150" }, { name: "Bob", description:"我是一個後端工程師", imageUrl: "https://via.placeholder.com/150" }, { name: "Stacy", description:"我是一個 PM", imageUrl: "https://via.placeholder.com/150" } ] return ( <div> <h1>我們的團隊</h1> {profileData.map(profile => ( <ProfileCard key={profile.name} name={profile.name} description={profile.description} imageUrl={profile.imageUrl} /> ))} </div> ); } export default App; ``` ## 核心概念 (二) - 狀態與生命週期 (State & Hooks) ### State (狀態):讓元件擁有自己的「記憶體」 * 概念: 讓元件「記住」事情的機制(例如:計數器、輸入框的文字)。 * 關鍵: 當 State 改變時,React 會自動重新渲染 (Re-render) 元件。 (這是 React 的魔法核心!) 那我們要怎麼去讓元件自己的狀態呢 ? 這時候 Hooks 登場了 ### Hooks 登場:讓函式元件 (Functional Component) 擁有超能力 #### useState(): * 功能:讓元件能夠有自己的狀態 (state) * 範例:以下是一個簡單的「計數器」按鈕,展示 [count, setCount] 的用法。 ```javascript= import React from "react"; export default function CustomizedButton() { const [count, setCount] = React.useState(0) const clickHandler = () => { setCount(count + 1); } return ( <div> <h1>This Button has State</h1> <button onClick={clickHandler}>Click Count : {count}</button> </div> ) } ``` #### useEffect(): * 功能:處理「副作用」(Side Effects)。 * 什麼是副作用? 就是任何「渲染畫面」以外的事情。 * 常見的副作用: * 向資料庫讀取資料 (Data Fetching)。 * 設定計時器 (<code>setTimeout</code>)。 * 手動操作 DOM。 * 總之,<code>useEffect</code>就是將這些 **「與渲染無關,但又必須執行的操作」** 從純粹的渲染邏輯中分離出來,並允許你在組件的生命週期(掛載、更新、卸載)中,以可預測且受控的方式執行它們。 * 範例:以下是一個簡單的 data fetch 模擬並且記錄 data fetching 的次數。 ```javascript= import React from "react"; export default function CustomizedButton() { const [count, setCount] = React.useState(0) const [toggle, setToggle] = React.useState(false); const clickHandler = () => { setCount(count + 1) setToggle(!toggle); } // Mocking data fetching with useEffect React.useEffect(() => { let message = "Data fetching..."; console.log(message); const timer = setTimeout(() => { message = "Fetching complete!"; console.log(message); }, 2000); return () => { clearTimeout(timer); } }, [toggle]); return ( <div> <h1>This Button has State</h1> <button onClick={clickHandler} className="custom-btn">Fetch Count : {count}</button> </div> ) } ``` ## 核心概念 (三) - React 的「快」,為什麼? * Virtual DOM (虛擬 DOM) * 問題: 頻繁且大量地直接操作「真實 DOM」非常昂貴(效能差)。 * React 的解法: * 在 JavaScript 記憶體中,建立一個「虛擬」的 DOM 結構 (V-DOM)。 * 當 State 改變時,React 建立一個 新的 V-DOM。 * Diffing Algorithm (差異比對): React 快速比對「舊 V-DOM」和「新 V-DOM」的差別。 * Reconciliation (調節): 只把 真正有改變 的部分,一次性地更新到「真實 DOM」上。 * 比喻: 你不是重蓋整棟房子(**操作 Real-DOM**),你只是找到哪片油漆剝落了,然後只補那塊漆(**操作 Virtual DOM**)。 --- 文件參考:https://react.dev/reference/react