Understanding React Hooks

source

After spending a few weeks working with and learning React Hooks, I wanted to collate it all into a quick cheatsheet for myself, I hope you can find some value in it.

Insights

  • Can refactor all class components to function components
    • Ended up with lower filesizes of >15%
  • Simpler lifecycle methods
  • Everything is so much nicer now

Hooks

useState

  • replaces all state functions
  • type should easily be inferred based on initial value but still worth setting
const [age, setAge] = useState < number > 28

return (
  <Fragment>
    <p>I am {age} Years of Age</p>
    <button onClick={() => setAge(age + 1)}>Get older! </button>
  </Fragment>
)

useEffect

  • combines componentDidMount and componentWillUnmount andcomponetnDidUpdate
  • no types needed
useEffect(() => {
  // do something on mount
  return () => {
    // do something on unmount (cleanup)
  }
}, []) //listen for change to x in [array] then trigger (update), empty for only mount / unmount

useRef

  • usually used for referencing dom nodes
    • null can be used as the initial value and a generic html can be used for the ref type
  • Replaces createRef
  • Can also be used as a replacement for instance properties on classes
    • Type should be inferred
const MyInput = () => {
  const inputRef = useRef < HTMLInputElement > null
  return <input ref={inputRef} />
}

useMemo / useCallback

  • shorthand for memoising functions _ types inferred _ make sure to specify the types of the parameters of the callback for useCallback, otherwise they will be set to any
const value = 10
// inferred as number
const result = useMemo(() => value * 2, [value])

const multiplier = 2
// inferred as (value: number) => number
const multiply = useCallback((value: number) => value * multiplier, [multiplier])

useReducer

  • Exactly like a redux router
    • Typed in the same way
interface State {
  value: number;
}

type Action =
  | { type: 'increment' }
  | { type: 'decrement' }
  | { type: 'incrementAmount', amount: number }

const counterReducer = (state: State, action: Action) => {
  switch (action.type) {
    case 'increment':
      return { value: state.value + 1 }
    case 'decrement':
      return { value: state.value - 1 }
    case 'incrementAmount':
      return { value: state.value + action.amount }
    default:
      throw new Error()
  }
}

const [state, dispatch] = useReducer(counterReducer, { value: 0 })

dispatch({ type: 'increment' })
dispatch({ type: 'decrement' })
dispatch({ type: 'incrementAmount', amount: 10 })

// TypeScript compilation error
dispatch({ type: 'invalidActionType' })

useContext

  • infer its types based on the context object that is passed in

const ThemeContext = React.createContext('light')

const Display = () => {
  const theme = useContext(ThemeContext)
  return (
    <div
      style={{
        background: theme === 'dark' ? 'black' : 'papayawhip',
        color: theme === 'dark' ? 'white' : 'palevioletred',
        width: '100%',
        minHeight: '200px',
      }}
    >
      {'The theme here is ' + theme}
    </div>
  )
}

useDebugValue

  • used for displaying values in React Developer Tools
  • type is inferred
const date = new Date()
useDebugValue(date, date => date.toISOString())

Resources