React 中 useContext 跟 React-MobX 的差異
useContext
跟 React-MobX 的差異
React 中 useContext
useContext
是 react 提供的一個 hook,可以讓我們透過讀取和訂閱元件中 context
共享元件之間的資料,主要是用來解決狀態提升和 prop drilling 的問題(即層層傳遞 props)。
1const AuthContext = createContext(null);23export default function App() {4 const [currentUser, setCurrentUser] = useState("");5 console.log("App rendered");6 return (7 <AuthContext.Provider value={{ currentUser, setCurrentUser }}>8 <Form />9 </AuthContext.Provider>10 );11}1213function WelcomeCard() {14 const { currentUser, setCurrentUser } = useContext(AuthContext);15 console.log("WelcomeCard rendered");16 return (17 <div>18 <h1>Welcome, {currentUser}!</h1>19 <button onClick={() => setCurrentUser("")}>Log out</button>20 </div>21 );22}2324function News() {25 console.log("News rendered");26 return (27 <div>28 <h1>Latest News</h1>29 <ul>30 <li>ewrweorjewoirj</li>31 <li>ewwwwwrj</li>32 <li>wjwirjwi</li>33 </ul>34 </div>35 );36}3738function Form() {39 const { currentUser, setCurrentUser } = useContext(AuthContext);40 const [name, setName] = useState("");4142 function handleSubmit(event) {43 event.preventDefault();44 setCurrentUser(name);45 }46 console.log("Form rendered");47 return (48 <section>49 {currentUser && <WelcomeCard />}50 {!currentUser && (51 <form onSubmit={handleSubmit}>52 <div>53 <label name="username">54 username55 <input56 type={"text"}57 id="username"58 onChange={(event) => setName(event.target.value)}59 />60 </label>61 </div>62 <button type="submit">Log in</button>63 </form>64 )}65 <News />66 </section>67 );68}
在這例子中,使用 useContext 實作了一個簡單的登入表單,當使用者輸入名稱後,點擊登入按鈕,就會顯示歡迎卡片,並且可以登出。
在 App 元件中,使用 AuthContext.Provider
提供了 currentUser
和 setCurrentUser
兩個方法,透過 useContext
可以在子元件中取得這兩個方法。
子元件透過 setCurrentUser
方法,可以改變 AuthContext
的 currentUser
的值,並且重新 render 子元件。
透過 Context 傳遞資料
在 WelcomeCard
中,我們透過 useContext
取得 currentUser
和 setCurrentUser
,不需要透過 props 傳遞資料,就可以取得 currentUser
的值。
Context
的值
更新 在 App 元件中,<AuthContext.Provider value={{ currentUser, setCurrentUser }}></<AuthContext.Provider>
向下子元件提供 AuthContext
的初始值 currentUser
與更新方法 setCurrentUser 。
在 Form
元件中,我們透過const { currentUser, setCurrentUser } = useContext(AuthContext);
去取得 currentUser
和 setCurrentUser
,並且在 handleSubmit
方法中,透過 setCurrentUser(name)
去更新 AuthContext
的currentUser
的值。
Context
的值改變時,會 re-render 子元件
當 接續上方,當提交表單後,currentUser
的值改變,AuthContext
的 currentUser
的值也會改變,這時候從 AuthContext
所在的元件 App
向下開始 re-render,並且接續 re-render 子元件 Form
、 WelcomeCard
、News
。
React-MobX
React-MobX 是一個 React 應用程式狀態管理的工具,透過觀察者模式,當 MobX 狀態變更時元件可以自動更新 UI,不需要手動去更新元件。
1const Board = observer(() => {2 console.log("Board rendered");3 return <h1>Count: {counterStore.count}</h1>;4});56export default function App() {7 console.log("App rendered");8 return (9 <div>10 <h1>MobX-State-Tree 計數器範例</h1>11 <Board />12 <Counter />13 </div>14 );15}
1// 定義一個 Counter 模型2const CounterModel = types3 .model({4 count: types.number, // 可觀察的狀態5 })6 .actions((self) => ({7 // 定義 action 來修改狀態8 increment() {9 self.count += 1;10 },11 decrement() {12 self.count -= 1;13 },14 }));1516// 創建模型實例17const counterStore = CounterModel.create({18 count: 0,19});2021export default counterStore;
-
使用了 mobx-state-tree 來定義一個結構化的狀態樹
CounterModel
,其中有一個count
狀態和兩個修改該狀態的 action (increment
和decrement
)。 -
使用
types.model
定義 MobX-State-Tree 模型,然後通過 actions 來定義修改狀態的方法。
1// observer 使 React 元件能觀察 MobX 的狀態變更2// 引入剛才定義的 store34const Counter = observer(() => {5 console.log("Counter rendered");6 return (7 <div>8 <button onClick={() => counterStore.increment()}>Increment</button>9 <button onClick={() => counterStore.decrement()}>Decrement</button>10 </div>11 );12});1314export default Counter;
-
使用 observer 讓 React 元件能夠觀察並反應 MobX-State-Tree 狀態的變化。當
counterStore.count
改變時,React 元件會自動重新渲染。 -
透過按鈕點擊來觸發
increment
和decrement
action,這些方法會自動更新狀態。 -
在這個例子中,只會重新渲染
Board
元件,不會像使用useContext
一樣向下更新使用該context
的子元件。
useContext
和 React-MobX 的差異
特性 | useContext | React-MobX |
---|---|---|
狀態管理範圍 | 可以包裹在特定 component tree ,範圍靈活 | 只能在全域最上層 |
狀態變更與更新機制 | 當 context 的值更新時,所有使用該 context 的元件都會重新渲染,無論這些組件是否實際依賴被更新的值。 | 僅重新渲染觀察到狀態變更的元件,精細控制渲染粒度 |
應用場景 | 適合多語系、主題等較簡單的全域性的狀態管理 | 適合較大型的應用程式,需要更細粒度的狀態管理 |