總會有更好的寫法。
簡述
因為自己用到 useContext
的頻率不高,所以在用的時候都用比較正統的方式來撰寫。
到了現在才發現原本有一種更好的寫法,可以把邏輯交給 Context 自己來處理,而不是寫在根元素上。總之這是個蠻不錯的練習,所以想記錄一下。
原本的寫法
假設有一個可以自定義主題的 Context,那最正統的寫法會像這樣:
1 | import { ThemeContext } from "../contexts/ThemeContext" |
這樣子寫是沒什麼不對,但有幾個缺點:
Context
的邏輯必須跟App
寫在一起。想想看當App
有其他邏輯的話,是不是有點混亂?- 延續第一個問題,當有別的
Context
也放在 App 時,就會參雜更多邏輯跟各種Provider
。
基於以上兩點,所以才會有接下來要介紹的寫法,讓你可以把「邏輯封裝在 Context 本身」,而不是混在一起大雜燴。
更好的寫法
這種作法就是當我們在建立 Context 時,順便建立一個「專屬 Context 的元件」,聽起來有點莫名,但你看 code 就應該懂了:
1 | // contexts/ThemeContext |
接著 App 的部分就可以改寫成這樣:
1 | import { ThemeProvider } from "../contexts/ThemeContext" |
應該一眼就能看出這跟原本的差別了吧?現在這個明顯乾淨很多,而且日後要維護的話就只要到對應的 Context 去修改就好,簡直一舉兩得。
不過說穿了我們只是巧妙的運用了 children
來包裝而已,其實跟原本的寫法做的事情一模一樣。
Bonus:使用 custom hook 來減少 boilerplate
在存取 Context 的時候,我們多半會這樣寫:
1 | import { useContext } from "react" |
這樣當然沒問題,但就是每次都要 useContext
跟 ThemeContext
有點小麻煩而已。
所以我們可以用 custom hook 來做包裝,像這樣:
1 | // hooks/useTheme.js |
接著就可以直接拿來用了:
1 | import { useTheme } from "hooks/useTheme" |