React Fundamentals

Components

function Hello() {
    return <h1>Hello from a component!</h1>;
}

export default Hello

使用元件:

import Hello from "./components/Hello";

function App() {
  return (
    <> 
      <Hello />
    </>
  )
}

React.memo

  • 用途: 用於包裹函數元件,以防止在 props 沒有更改的情況下對元件進行不必要的重新渲染。
const MyComponent = React.memo((props) => {
    return <div>{props.value}</div>;
});

Use Case: 當你有一個函數元件,且你確信其 props 在某些情況下不會改變時,可以用來優化渲染效能。

Props

在元件之間共享的唯讀屬性。
父元件可以傳送資料給子元件。
<Component key=value />
// App.jsx
function App() {
  return (
    <>
      <Hello name="ABC" msg="Here" emoji="💥" />
      <Hello name="XYZ" msg="Nothing" emoji="🎇" />
    </>
  );
}

// Hello.jsx
function Hello({ name, msg, emoji }) {
  return (
    <div>
      <h1>
        Hello {name}, {msg} {emoji}
      </h1>
    </div>
  );
}

Immutability

不可變性

function Hello(props) {
  // props.name = "Replace"; // Error: Uncaught TypeError: "name" is read-only
  return (
    <div>
      <h1>
        Hello {props.name}, {props.msg} {props.emoji}!
      </h1>
    </div>
  );
}

PropTypes

一種確保傳遞的值具有正確資料類型的機制。

age: PropTypes.number

Lists & Keys

export default function Fruits() {
  const fruits = ["Apple", "Mango", "Orange", "Banana", "Pineapple"];
  return (
    <div>
      <ul>
        {fruits.map((fruit) => (
          <li key={fruit}>{fruit}</li>  // 正確: 加上唯一的 key
        ))}
      </ul>
    </div>
  );
}

Portal

  1. Modal/Dialog (對話框)

    • 確認對話框
    • 訊息提示
    • 表單輸入
  2. 懸浮元素

    • Tooltip (工具提示)
    • Dropdown Menu (下拉選單)
    • Select 下拉選單
    • DatePicker (日期選擇器)
  3. 全域通知

    • Toast 通知
    • 錯誤訊息
    • Loading 狀態
  4. 特殊 UI

    • 右鍵選單 (Context Menu)
    • 虛擬鍵盤
    • 圖片預覽
    • 影片播放器
    • 拖拽選單
  5. 特殊情境

    • iframe 內的元素
    • Shadow DOM 外的元素
    • 第三方套件整合

使用時機:

  • 需要跳出當前 DOM 階層限制
  • 避免 z-index/overflow 問題
  • 需要共享全域 UI 元件
  • 需要整合不同框架的元件

Hooks

useState

允許建立狀態變數以及一個 setter 函數,用於在虛擬 DOM 中更新其值。
import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
  • Native (原生 JS 對比)
<p id="count">Count: 0</p>
<button id="increment">Increment</button>
<script>
  let count = 0;
  document.getElementById('increment').addEventListener('click', function() {
    count++;
    document.getElementById('count').textContent = 'Count: ' + count;
  });
</script>

useEffect

  • 作用

    • 事件監聽 (Event Listeners)
    • DOM 操作
    • 訂閱服務 (Subscriptions, 如實時更新)
    • 從 API 獲取資料
    • 元件卸載時的清理工作
  • 告訴 React 在什麼時候執行程式碼

    • 當元件重新渲染時
    • 當元件掛載時
    • 當特定值的狀態改變時
useEffect(() => {})           // 每次渲染後執行
useEffect(() => {}, [])       // 僅在掛載時執行一次
useEffect(() => {}, [value])  // 掛載時 + 當 value 改變時執行
function DataFetcher() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => setData(data));
  }, []); // 空陣列表示只在元件掛載時執行一次
  return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
}

useRef

當其值改變時不會引起重新渲染。
當你希望元件記憶某些資訊,但不希望該資訊觸發新的渲染時使用。
  • Use Cases
    • 存取 / 互動 DOM 元素
    • 處理焦點 (Focus)、動畫和過渡
    • 管理計時器 (Timers) 和間隔 (Intervals)
function FocusInput() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}

useContext

允許你在多層元件之間共享值,而不需要透過每一層手動傳遞 props。
  • 使用情境
    • 全域狀態 (如佈景主題、語言切換)
    • 不同階層元件間的資料傳遞

Provider

// 建立 Context 並提供值

Consumer

// 使用 Context 中的值

useMemo

  • 作用:
    • 效能優化,避免不必要的重複計算
    • 快取 「計算結果」
  • 使用情境:
    • 避免在重新渲染中執行昂貴的計算
    • 優化大型資料列表的渲染
const memoizedValue = useMemo(() => {
    return complexCalculation(a, b); // 快取計算結果
}, [a, b]);

useCallback

  • 作用:
    • 效能優化,避免不必要的函數重新建立
    • 快取 「函數本身」
  • 使用情境:
    • 當需要將函數作為 props 傳遞給子元件時(搭配 React.memo)
    • 確保函數參照穩定,防止子元件不必要的重新渲染
const memoizedCallback = useCallback(() => {
    doSomething(a, b); // 快取函數參照
}, [a, b]);

useReducer

  • 作用: 管理複雜的狀態邏輯。
  • 使用情境:
    • 多步驟表單
    • 圖片拖拽功能
    • 複雜的狀態切換邏輯(類似 Redux)

useImperativeHandle

  • 作用: 自定義由父元件可以存取的子元件實例值。
  • 使用情境:
    • 隱藏子元件內部實作,只暴露特定方法(如手動觸發子元件動畫)
    • 複雜的可操控元件(如自定義彈窗操控)

useLayoutEffect

  • 作用: 在 DOM 更新後但在瀏覽器繪製前同步執行。
  • 使用情境:
    • 確保在 DOM 渲染後立即進行測量或修正
    • 實作複雜的同步動畫或佈局邏輯

useId

  • 作用: 產生唯一的、穩定的 ID。
  • 使用情境:
    • 產生多個元素的唯一 Key 值
    • 關聯表單標籤與輸入欄位的存取性

useTransition

  • 作用: 管理非阻塞的過渡性 UI 更新。
  • 使用情境:
    • 在分頁切換時顯示過渡狀態
    • 優化高頻率計算結果的延遲渲染

useDeferredValue

  • 作用: 延遲更新某個值,以提升效能。
  • 使用情境:
    • 避免快速輸入時的 UI 卡頓
    • 高效能的需求搜尋輸入框

useSyncExternalStore

  • 作用: 訂閱外部資料源,並保持資料同步。
  • 使用情境:
    • 自定義全域狀態管理工具
    • 連接第三方資料庫(如 Redux)

useInsertionEffect

  • 作用: 在 DOM 變更前注入 CSS 樣式。
  • 使用情境:
    • 動態插入樣式(如 Emotion 或 styled-components)

學習順序 (Orders)

  1. 初學: 掌握最常用的 Hooks

    • useState
    • useEffect
    • useContext
  2. 進階: 學習效能優化相關 Hooks

    • useMemo
    • useCallback
    • useRef
  3. 專家: 處理複雜狀態與邏輯的 Hooks

    • useReducer
    • useImperativeHandle
  4. 特定用途: 學習應對特殊場景的 Hooks

    • useLayoutEffect
    • useTransition
    • useDeferredValue
    • useSyncExternalStore
    • useInsertionEffect
    • useId
  • useStateuseReducer 用於管理元件內部的狀態。
  • useEffect, useLayoutEffect, useInsertionEffect 均用於處理副作用,差別在於執行時機。
  • useContext 用於跨元件共享資料。
  • useRefuseId 用於管理參照與唯一識別碼。
  • useTransitionuseDeferredValue 用於效能優化,降低不必要的 UI 阻塞。
  • useSyncExternalStore 用於訂閱外部(非 React)的狀態。

Purity (純粹性)

React 元件應該是純函數:

function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}
  • Native (原生 JS 對比)
<h1 id="greeting"></h1>
<script>
  let name = 'Alice';
  document.getElementById('greeting').textContent = 'Hello, ' + name + '!';
</script>

Strict Mode

import React from 'react';

function MyApp() {
  return (
    <React.StrictMode>
      <App />
    </React.StrictMode>
  );
}

特性說明

  • 開發模式下,某些生命週期會被執行兩次
  • 幫助檢查副作用是否純粹
  • 識別過時的 API 使用與不安全的生命週期

Fragments

function List() {
  return (
    <>
      <li>Item 1</li>
      <li>Item 2</li>
    </>
  );
}

Context API

const ThemeContext = createContext();

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

function ThemedComponent() {
  const { theme, setTheme } = useContext(ThemeContext);
  return (
    <div>
      <p>Current Theme: {theme}</p>
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        Toggle Theme
      </button>
    </div>
  );
}

Portals

function Modal() {
  return ReactDOM.createPortal(
    <div className="modal">This is a modal</div>,
    document.getElementById('modal-root')
  );
}

Error Boundaries

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    console.error(error, info);
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

Suspense

import { Suspense, lazy } from 'react';

const LazyComponent = lazy(() => import('./LazyComponent'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <LazyComponent />
      </Suspense>
    </div>
  );
}

Event Handlers (事件處理器)

主要用於 input, textarea, select, radio 等表單元素
每當輸入值改變時觸發函數

Mouse Events

  • onClick
  • onDoubleClick
  • onMouseDown
  • onMouseUp
  • onMouseMove
  • onMouseEnter
  • onMouseLeave
  • onMouseOver
  • onMouseOut
  • onContextMenu

Form Events

  • onChange
  • onSubmit
  • onReset
  • onInvalid
  • onSelect

Focus Events

  • onFocus
  • onBlur

Keyboard Events

  • onKeyDown
  • onKeyUp
  • onKeyPress

Clipboard Events

  • onCopy
  • onCut
  • onPaste

Touch Events

  • onTouchStart
  • onTouchMove
  • onTouchEnd
  • onTouchCancel

Drag & Drop Events

  • onDrag
  • onDragStart
  • onDragEnd
  • onDragEnter
  • onDragLeave
  • onDragOver
  • onDrop

Media Events

  • onPlay
  • onPause
  • onPlaying
  • onEnded
  • onLoadStart
  • onLoadedData
  • onLoadedMetadata
  • onError
  • onVolumeChange
  • onTimeUpdate
  • onSeeking
  • onSeeked

Animation Events

  • onAnimationStart
  • onAnimationEnd
  • onAnimationIteration

Transition Events

  • onTransitionEnd
  • onTransitionStart

Scroll Events

  • onScroll
  • onWheel

Window Events

  • onResize
  • onError
  • onLoad
  • onUnload
  • onBeforeUnload

Visibility Events

  • onVisibilityChange

Image Events

  • onLoad
  • onError

OnChange

function TextInput() {
  const [value, setValue] = useState('');
  
  function handleChange(e) {
    setValue(e.target.value);
  }
  
  return <input value={value} onChange={handleChange} />;
}

React Query

  • 專門用於處理 Server Side 資料
    • API 請求
    • 資料快取
    • 資料同步
    • 錯誤重試
    • 狀態更新

Tanstack Router

zustand

  • useShallow
    • 淺層比較訂閱的 state,減少不必要的重新渲染
    • 對於物件或陣列型的 state 特別有用
    • 類似於 React.memo 的比較邏輯

Middleware

immer

  • 允許以可變的方式編寫不可變的更新
  • 簡化複雜狀態的更新邏輯
  • 自動處理不可變性 (Immutability)

subscribeWithSelector

  • 可以指定監聽特定的 state 變化 / 指定特定條件下觸發訂閱

devtools

  • 與 Redux DevTools 整合
  • 支援時光倒流調試
  • 可以查看狀態變化的歷史紀錄

persist

  • 提供狀態持久化功能
  • 可自定義存儲引擎
  • 支援加密與壓縮

App.jsx
test.jsx