在 React 元件之間,如果要傳遞資料,很直覺會想到 props,一個一個往下傳遞。但有時候考量到層級很多很深,如果一個資料要從第一層往下送到第五層,總感覺十分吃力不討好啊!
這種情況下,使用 context 是否有機會解決這個問題呢?
在 React 中,以元件(component)為單位組合成元件樹,而元件與元件之間若要傳遞狀態或數值,一般會使用 props 來傳遞,好處是相當直覺,像是一盆水從樹頂澆下去,水會由上往下流,也符合 React 單向資料流的概念,可以讓元件之間的關係變得簡單可預測。
不過隨著元件樹愈長愈大棵,總是會有一些資料,幾乎每個元件都有它的蹤跡,比如使用者偏好、時區、app theme 等,如果透過 props 層層傳遞,這些資料就需要從 app root 的位置,不斷往下傳給其他元件,直到傳到末端的元件為止,過程可能經過數十層元件也不為過。
一方面程式會變得非常冗長,props 傳下去就十幾二十個參數,而且很多參數可能自己也用不到;另一方面要擔心中間有無漏傳,或者程式更新不小心動到,都需要花很多心力去維護。
React 提出的 context 概念如下:
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
白話就是,提供了另一種方式,可以不用層層傳遞,就直接送資料到目的地元件。
聽起來像是過海關可以走特別通道一樣,但其實 context 是運用了 provider 的 design pattern,透過 react.createContext()
產生 context,放在 Provider 之後,在 Provider 底下的所有元件(即 Consumer),都可以透過 useContext
來取得資料。
如果說 props 像是用水澆下去,那 context 則像是打一盞燈,直接照射。
由於 context 發生變化時,會觸發 consumer 元件們重新 render,且難以追溯更動點,因此較適合「幾乎不更動」的資料,比如多國語系、使用者設定、theme 等,大多是「只供讀取」(readonly)的比較適合。
其實 props 也不是只有單純傻傻往下傳一種方式,如果今天只是單純要將多個 props 從第一層傳到第五層,React 官方也提供了另一個 component composition 的思維,透過依賴反轉的方式,在第一層就先將這些 props 組合成一個,甚至直接組成元件,將元件當作 props 往下傳,也是一種方法。
整體來說,context 提供了一種方式,用來在跨層級的多個元件中,分享一個比較全域的資料,當然透過 context 的方式雖然方便,但也承受一些風險(如上述缺點),只要使用者善用在對的情境,缺點也不再是缺點啦~
另外,找資料的時候意外發現一個很有趣的討論,是否有想過既然 context 到處都可以用,那跟「全域變數」又有什麼差別呢?有興趣的話可以先想想,再點進去看看哦!