昨天看完簡單到有點出奇的useRef
,今天來看基礎的useContext
吧!
React的context可以讓我們避免prop drilling的問題,不用一直將prop傳到子層的子層的子層的子層...(略),而是在需要使用的元件,使用useContext
取得要用的值即可。
為了示範方便,讓我們一樣用App.tsx檔案來做範例吧,但正常開發時,通常會選擇將context另外放一個資料夾,比較方便管理。(React資料夾結構設計,各有擁護者,這邊就不贅述了。)
在App.tsx裏,寫下這些未完成的code:
import { useContext, createContext, useState } from "react"
const defaultInfoValue = { name: "John", age: 18 }
const InfoContext = createContext<typeof defaultInfoValue>(defaultInfoValue)
const App = () => {
return (
<InfoContext. //不打完
)
}
export default App
在上面,我們做了:
宣告了一個預設值defaultInfoValue
,並將他傳入createContext
當做InfoContext
的起始值。
這邊我們刻意明確的將InfoContext
的型別宣告為<typeof defaultInfoValue>
,因為我已經有了一個類似形狀的物件defaultValue
,所以我透過關鍵字typeof
(可以回去看看第20天的文章),取得特定變數defaultValue
的型別形狀。
你在這邊沒有強制宣告型別是沒有關係的,但要是能明確一點也不是什麼壞事。
在未完成的App
元件的return statement當中,有一個沒打完的<InfoContext.
,打到這邊,你會發現,編輯器又提示了我們,有哪些東西是能從InfoContext
中取用的了!有Consumer
、Provider
、displayName
,這邊我們只需要使用Provider
即可,因為我們要設定一個值,讓子層的任何元件都能取用得到。(displayName
我還是看了型別宣告檔才知道他要幹嘛,簡單來說,在你設定名稱後,你能在react devTool中清楚看到這個context的名稱。)
讓我們繼續吧:
//略過import
//你後來會發現,我們這行設定的預設值都不會用到,但我們還是能用這些值來設定型別
const defaultInfoValue = { name: "John", age: 18 }
const InfoContext = createContext<typeof defaultInfoValue>(defaultInfoValue)
const AnotherComponent = () => {
//這邊不主動宣告型別也是可以,但我還是想寫清楚
const info = useContext<typeof defaultInfoValue>(InfoContext)
return (
<>
<div>{info.name}</div>
<div>{info.}</div> //沒打完
</>
)
}
const App = () => {
const [info, setInfo] = useState<typeof defaultInfoValue>({
name: "Allen",
age: 200
})
return (
<InfoContext.Provider value={info}>
<AnotherComponent />
</InfoContext.Provider>
)
}
再接續剛剛的話題,我們透過Provider
,便能將特定的值給傳到子層去。傳遞方法就是將值傳到value這個key中。這邊我們使用了用useState
初始化的值,並且主動的宣告了他的型別為:"跟defaultInfoValue
一樣的型別",然後“再次”給他了"初始值"(??)。
所以你會注意到,最早的defaultInfoValue
已經被覆蓋過去不太重要了,他現在唯一的功能就是提供初始的物件型別形狀而已。
在App上方,我另外宣告了一個元件AnotherComponent
,並在內部使用useContext
,需要傳入的值,當然是我們早前用createContext
創立的context(好饒口),所以會變成useContext(InfoContext)
,如此一來,我們就得到了內含name
跟age
的info
物件!
在return statement當中,取用info物件時,你又能發現,編輯器又幫我們推薦能使用的方法/屬性了!
所以,TypeScript與useContext
之間的關係,就是這麼簡單。你一定會說:現實中的專案哪有怎麼單純的context。但擁有了我們先前講到的「透過hover去看編輯器預期的型別」,以及閱讀型別宣告檔的經驗,你應該能主動擴充任何的context而不報錯。
在這篇文章,我們順利看了useContext
怎麼跟TypeScript結合,還順便複習了typeof
關鍵字於TypeScript內的用法,且再次發現編輯器有多麽好用。
那我們明天繼續看別的hook吧!