---
title: "React 學習筆記 - 何謂 React Hook、副作用、Loading、錯誤處理、上下文關係(Context) - Part's 4"
description: "React 學習第四篇，介紹 React Hook 概念、useEffect 副作用處理、Loading 狀態管理、錯誤邊界，以及 Context API 的上下文關係應用。"
canonical_url: "https://blog.markkulab.net/post/learn-react-part-4"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/author/mark-ku"
site: "Mark Ku's Blog"
date_published: "2022-07-24 01:03:01 +0800"
category: "Frontend"
tags: ["react", "hook", "useeffect", "context", "frontend", "javascript", "學習筆記"]
language: "zh-TW"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "轉載或引用請註明作者並附上原文連結"
---

# React 學習筆記 - 何謂 React Hook、副作用、Loading、錯誤處理、上下文關係(Context) - Part's 4

## 何謂 React Hook 
Hook 是 React 16.8 中增加的新功能。它讓你不必寫 class 就能使用 state 以及其他 React 的功能。 (from 官方文件)  
並「函式」來複用邏輯的概念，重新設計元件，更新粒度更細，讓程式碼更清晰, 並逐步將 class component 替換成函式型元件 Function Component。，簡單來說就是沒有template的組件，方便用於狀態及邏輯覆用。
 
## 何副作用 Effect
呼叫同個方法，給同樣的參數，永遠應該返回同樣的值，react 元件中，給相同的 props ，渲染的 ui應該永遠一樣，但副作用和純函數相反，還處理了和返回值無關的事。簡單來說副作用，會去觀測監測值的變化，來做指定的事。

## useEffect 異步存取資料
```
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `點擊${count}`;
  }, [count]);
```
  
P.S. useEffect 若不帶第二個參數，每次被渲染就會被調用，會造成無窮無死循環，若不想發生可以給他空 array。  
P.S. useEffect watch 空 array 時，他只會初始化一次，在 Next JS 時可以當來用戶端初始化事件。
![useEffect 程式碼缺少第二個參數導致無限呼叫](https://blog.markkulab.net/content/markku/posts/learn-react-part-4/images/915DCg8.png)

## 因為 useEffect 是同步方法，但可以用直接 promise，如果要用 async wait，則必在 useEffect 裡擴充一個 async 方法，並執行他
 
 ```
 // promise 用法
 const responses = fetch(
      "https://jsonplaceholder.typicode.com/users"
    )
    .then(response => response.json())
    .then(data => setRobotGallery(data))
 ```
 或  
 ```
 // async await 用法
  useEffect(() => {
    const fetchData = async () => {
      const res = await fetch("https://jsonplaceholder.typicode.com/users");      

      const data = await res.json();
      setRobotGallery(data);
    };

    fetchData();
  }, []);
 ```
 
## Loading 
```
const [loading, setLoading] = useState<boolean>(false);
```
    
```    
{!loading ? (
        <div className={styles.robotList}>
          {robotGallery.map((r) => (
            <Robot key={r.id} id={r.id} email={r.email} name={r.name} />
          ))}
        </div>
      ) : (
        <h2>loading</h2>
)}
```

## 錯誤處理
```
 const [error, setError] = useState<string>();

 try {
       throw new Error("網站錯誤")               
} catch (e) {
 if (e instanceof Error) {
    setError(e.message);
    }
}      
    
{(!error || error !== "") && <div>{error}</div>}
```

## 上下級元件參數傳遞

### 一般來說可以透過 props  傳遞參數到子元件，但自身不需要这个prop，但为了使子组件能获取到这个prop，則會衍生 Prop Drilling 的問題。

```
<component test="" />
add perpery props interface 
React.FC<props>
``` 
P.S. Prop Drilling 簡而言之是指：當一個元件自身不需要這個prop，但為了使子元件能獲取到這個prop，而不得已去傳遞這個prop的行為。

### 這時就可以用 React 上下文關係 context  
``` 
const defaultContextValue = {
  username: "阿來克斯",
};

export const appContext = React.createContext(defaultContextValue);

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
    <appContext.Provider value={defaultContextValue}>
      <App />
    </appContext.Provider>
  </React.StrictMode>
);
```    

使用的元件
```    
import { appContext } from "../index";
<appContext.Consumer>
      {(value) => {
        return (
          <div className={styles.cardContainer}>            
            <p>{value.username}</p>
          </div>
        );
      }}
</appContext.Consumer>
```
    
#### useContext Hook 簡化寫法，可以不用層層套崁
```
onst Robot: React.FC<RobotProps> = ({ id, name, email }) => {
const value = useContext(appContext)

  return (        
          <div className={styles.cardContainer}>
            <img alt="robot" src={`https://robohash.org/${id}`} />
            <h2>{name}</h2>
            <p>{email}</p>
            <p>{value.username}</p>
          </div>            
  );
};
```
P.S. 那麼如果，組件若不是上下級關係時，又不想一層層傳進去，則需要考慮用 redux 這種狀態管理的機制進行管理

---

## 關於本文與作者

本文出自 [Mark Ku's Blog](https://blog.markkulab.net/post/learn-react-part-4)

授權條款： [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — 轉載或引用請註明作者並附上原文連結

### 關於作者

**[Mark Ku](https://blog.markkulab.net/author/mark-ku)** — Software Solution Provider

- 10+ 年資深軟體工程師，現為 AI 應用 Builder
- 專注大型平台架構設計，從北美電商到AI SaaS訂閱收費系統
- 結合 AI Agent 與自動化，打造高效可演進的產品技術基礎

### 作者開發的免費工具

以下工具皆可免費使用：

- [免費 PDF 簽名工具](https://blog.markkulab.net/tools/pdf-sign): 線上 PDF 簽名工具，瀏覽器內完成手繪、打字、上傳簽名，可拖曳放置、縮放、下載。所有處理都在你的裝置完成，檔案不會上傳。
- [VS Code Refactory](https://blog.markkulab.net/tools/refactory): Refactory 是一款 VS Code 重構擴充套件：34 個重構動作、37 條 code smell 檢查、Code Health 儀表板、18 種語言、534 支測試。懂你的專案慣例：介面放哪、DI 註冊寫在哪、'use client' 該不該加；還會用 git 修改頻率 × 複雜度排出「該先修哪個檔案」，並一鍵把壞味道交給你自己電腦上的 Claude Code 修。免費使用，原始碼不離開你的機器。
- [DB-Kit 資料庫管理工具](https://blog.markkulab.net/tools/db-kit): DB-Kit 是一個用 Tauri + Rust + React 打造的輕量跨平台資料庫管理工具，用單一一致的介面同時管理 MySQL、MariaDB、PostgreSQL、SQL Server、Oracle、SQLite、MongoDB、Redis、Kafka、Elasticsearch 與 RabbitMQ 十一種資料來源：連線密碼以 OS keychain 加密、SSH Tunnel、完整 CRUD、視覺化查詢建構器、多結果集同時顯示、跨連線資料傳輸與比對同步、Excel / CSV 匯入匯出、執行計畫視覺化、ER 圖、排程備份、SQL 壓力測試（p50～p99 延遲百分位）、15 條規則的 SQL 審查、Kafka 訊息瀏覽與監控告警；繁中 / 英文雙語介面，內建 AI 助手（自然語言生成 SQL、AI 審查與調校建議）與命令列工具 dbk。免費開源（MIT），提供 Windows / macOS / Linux 安裝檔。
- [VS Code Super Mermaid](https://blog.markkulab.net/tools/super-mermaid): Super Mermaid 是一款 VS Code 擴充套件：開箱即用的漂亮 Mermaid 圖表，自動上色、即時預覽、滑鼠平移縮放、PNG / SVG 高解析匯出，內建 21 種範本與多種主題。免費開源（MIT）。
- [React Super Mermaid](https://blog.markkulab.net/tools/react-super-mermaid): react-super-mermaid 是一個開源 React 元件庫：一行 <MermaidViewer> 即可渲染漂亮的 Mermaid 圖表，內建 colorful / sketch 主題、平移縮放、圖內搜尋、SVG / PNG 高解析匯出。輕量、SSR 安全、完整 TypeScript 型別。免費開源（MIT）。
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/tools/jira-super-mermaid): Atlassian Forge app：在 Jira issue 與 Confluence 內文直接寫 Mermaid 語法，畫流程圖、時序圖、狀態機與甘特圖。11 種圖表、SVG / PNG 匯出、明暗主題、完整中日韓文字支援。取得 Runs on Atlassian 資格：圖表存在你自己的站台，app 不呼叫任何第三方服務。免費，即將上架 Atlassian Marketplace。
- [Mermaid 線上預覽](https://blog.markkulab.net/tools/mermaid-preview): 在瀏覽器裡寫 Mermaid、即時看圖，整張圖表壓進網址就能分享。免註冊、不上傳伺服器，相容 mermaid.live 的分享連結。
- [React Intl Phone Number](https://blog.markkulab.net/tools/react-intl-phone-number): react-intl-phone-number 是一個開源 React 元件：framework-agnostic、不依賴 antd，提供 E.164 進出、可搜尋國旗 / 國碼下拉、可配置驗證等級（strict / mobile-strict / loose）、可主題化 CSS 與 i18n，電話邏輯由 google-libphonenumber 驅動。輕量、完整 TypeScript 型別。免費開源（MIT）。
- [Uptime Kuma Cluster](https://blog.markkulab.net/tools/uptime-kuma-cluster): 把單機版 Uptime Kuma 改造成高可用叢集：OpenResty + Lua 智慧負載平衡、MariaDB 共享狀態、健康檢查與自動 Failover，附叢集管理 REST API，一行 Docker Compose 啟動。免費開源（MIT）。
- [特教專案](https://blog.markkulab.net/education): 為特殊教育學生製作的學習教材

### 每日 Podcast

- [科技新鮮事](https://blog.markkulab.net/category/tech-news): 每日精選 AI 與科技趨勢，透過語音摘要快速掌握最新技術動態，涵蓋 AI 應用、軟體架構、DevOps 與工程實戰。 — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/category/ai-stock-chat): 每個交易日用 AI 分析台股盤勢，以雙人對話聊當天的盤中觀察與隔日預測。 — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml

### 電子報

[訂閱電子報](https://blog.markkulab.net/subscribe) — 第一時間收到新文章通知，無垃圾信、隨時可取消訂閱。
