Skip to content

Typescript: (6) Contexts and Refs

Mithi Sevilla edited this page Mar 30, 2021 · 1 revision

Context

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>
}

Refs

const Search = () => {
  const input = useRef<HTMLInputElement>(null)
  useEffect(() => {
    if(input.current) {
      input.current.focus()
    }
  }, [])

  return <form><input ref={input} type="type" /></form>
}