React 的數據傳遞流程
在 React 中,數據傳遞通常是自上而下的,也就是父組件把數據通過 props
傳遞給子組件,子組件無法直接修改父組件的數據。
例子:父組件向子組件傳遞數據
const Parent = () => {const user = { name: "John", age: 24 };return <Child user={user} />;
};const Child = ({ user }) => {return (<div><h2>姓名: {user.name}</h2><h2>年齡: {user.age}</h2></div>);
};
問題不大,看起來很簡單,對吧?
子組件傳遞數據的“噩夢”
但如果子組件需要修改父組件的數據,就必須通過回調函數,讓子組件把新的數據“反向”傳回父組件,讓父組件更新數據。
例子:子組件修改父組件數據
const Parent = () => {const [user, setUser] = useState({ name: "John", age: 24 });// 讓子組件調用這個方法來修改 userconst updateUser = (newName) => {setUser({ ...user, name: newName });};return <Child user={user} updateUser={updateUser} />;
};const Child = ({ user, updateUser }) => {return (<div><h2>姓名: {user.name}</h2><button onClick={() => updateUser("Alice")}>改名為 Alice</button></div>);
};
這樣,點擊按鈕后,John
就會變成 Alice
,但這還不算太糟糕。
真正的問題是:如果有很多層嵌套怎么辦?
多層嵌套時的“數據傳遞地獄”
如果 Child
不是直接在 Parent
里面,而是嵌套了好幾層,每一層都要手動傳 props
,就會變得非常痛苦。
數據傳遞“地獄”示例
const Parent = () => {const [user, setUser] = useState({ name: "John", age: 24 });const updateUser = (newName) => {setUser({ ...user, name: newName });};return <Level1 user={user} updateUser={updateUser} />;
};// 一層又一層地傳遞 props...
const Level1 = ({ user, updateUser }) => <Level2 user={user} updateUser={updateUser} />;
const Level2 = ({ user, updateUser }) => <Level3 user={user} updateUser={updateUser} />;
const Level3 = ({ user, updateUser }) => <Level4 user={user} updateUser={updateUser} />;
const Level4 = ({ user, updateUser }) => (<div><h2>姓名: {user.name}</h2><button onClick={() => updateUser("Alice")}>改名為 Alice</button></div>
);
問題:
- 你要在 每一層組件 都寫
props
傳遞,代碼變得冗長且難以維護。 - 組件越多,數據傳遞越混亂,很容易出錯。
- 這個問題被稱為 “Props Drilling”(屬性挖掘),就像挖礦一樣,數據要一層一層往下挖。
如何解決?—— useContext
來救場!
React 提供了 useContext
,它就像一個全局數據倉庫,可以讓任何組件直接訪問數據,而不需要層層 props
傳遞。
步驟 1:創建 Context
import { createContext, useState } from "react";// 1. 創建 Context
const UserContext = createContext();// 2. 創建 Provider 組件
const UserProvider = ({ children }) => {const [user, setUser] = useState({ name: "John", age: 24 });const updateUser = (newName) => {setUser({ ...user, name: newName });};return (<UserContext.Provider value={{ user, updateUser }}>{children} {/* 這里的 children 讓所有子組件都能訪問這個 Context */}</UserContext.Provider>);
};export { UserContext, UserProvider };
步驟 2:子組件直接用 useContext
讀取數據
import { useContext } from "react";
import { UserContext } from "./UserContext";const UserProfile = () => {const { user, updateUser } = useContext(UserContext);return (<div><h2>姓名: {user.name}</h2><button onClick={() => updateUser("Alice")}>改名為 Alice</button></div>);
};export default UserProfile;
步驟 3:在 App.js
里包裹 Provider
import React from "react";
import { UserProvider } from "./UserContext";
import UserProfile from "./UserProfile";const App = () => {return (<UserProvider><UserProfile /></UserProvider>);
};export default App;
為什么 useContext
很強大?
- 避免了“數據傳遞地獄”:不需要層層
props
傳遞,所有組件都能直接訪問數據。 - 代碼更清晰:不管組件嵌套多少層,都能方便地讀取和更新數據。
- 性能更好:不會因為
props
變化導致所有中間組件都重新渲染。
總結
-
傳統數據傳遞方式(
props
)- 適合小型項目,數據傳遞簡單時使用。
- 但是當層級變深時,
props drilling
讓代碼變得難以維護。
-
useContext
方式- 適合共享狀態的場景,比如用戶信息、主題設置、語言切換等。
- 讓所有組件都能直接訪問數據,避免
props
層層傳遞。
-
最佳實踐
- 如果數據只在父子組件之間傳遞,用
props
即可。 - 如果數據需要被多個組件共享,使用
useContext
來簡化代碼。
- 如果數據只在父子組件之間傳遞,用
🚀 現在,你可以擺脫“數據傳遞地獄”,用 useContext
讓 React 代碼更清爽!