-
Notifications
You must be signed in to change notification settings - Fork 39
Typescript: (6) Contexts and Refs
Mithi Sevilla edited this page Mar 30, 2021
·
1 revision
import * as React from "react"
import {useState, useEffect, ReactNode, useContext, createContext} from "react"
const defaultTheme = "white"
const ThemeContext = createContext(defaultTheme)
// context value is inferred as string here
type Props = { children: ReactNode }
const ThemeProvider = ({ children }: Props) => {
const [theme, setTheme] = useState(defaultTheme)
useEffect(() => {
// We can get the theme from local storage
// or web api but in this example it's hard coded
const currentTheme = "lightBlue"
setTheme(currentTheme)
}, [])
return <ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
}
// TYPE: const useTheme: () => string
// TYPE: const ThemeContext: React.Context<string>
// TYPE: useContext<string>(context: React.Context<string>): string
const useTheme = () => useContext(ThemeContext)
const Header = () => {
const theme = useTheme()
return <div style={{backgroundColor: theme }}> Hello! </div>
}
const App = () => <ThemeProvider><Header/></ThemeProvider>
Explicitly setting the context type
import * as React from "react"
import {useState, useEffect, ReactNode, useContext, createContext} from "react"
const defaultTheme = "white"
type ThemeContextType = {
theme: string
setTheme: (value: string) => void
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined)
type Props = { children: ReactNode }
const ThemeProvider = ({ children }: Props) => {
const [theme, setTheme] = useState(defaultTheme)
useEffect(() => {
const currentTheme = "lightBlue"
setTheme(currentTheme)
}, [])
return <ThemeContext.Provider value={{theme, setTheme}}>
{children}
</ThemeContext.Provider>
}
const useTheme = () => useContext(ThemeContext)
const Header = () => {
const { theme, setTheme } = useTheme()!
// what is this exclamation for???
// to tell the typescript compiler that its return value
// won't be undefined
return (
<div style={{backgroundColor: theme }}>
<p> Hello! </p>
<select value={theme} onChange={e => setTheme(e.currentTarget.value)}>
<option value="white"> WHITE </option>
<option value="blue"> BLUE </option>
<option value="green"> GREEN </option>
</select>
</div>
)
}
const Main = () => {
return <ThemeProvider> <Header /> </ThemeProvider>
}
const Search = () => {
const input = useRef<HTMLInputElement>(null)
useEffect(() => {
if(input.current) {
input.current.focus()
}
}, [])
return <form><input ref={input} type="type" /></form>
}