Hooked
on
useState

© 2022 Gabriel Dayley, Kyle West

hooks


import {
  useState,     // store data as state
  useEffect,    // "react" to state changes
  useRef,       // reference data outside of state
  useMemo,      // cache a value for performance
  useCallback,  // cache a function for performance
  useReducer,   // handle complex state updates
} from 'react'
© 2022 Gabriel Dayley, Kyle West

useState

Stores data as state

const [count, setCount] = useState(0)
const inc = () => setCount(count + 1)
const dec = () => setCount(count - 1)

// with callbacks:
const [count, setCount] = useState(() => 0)
const inc = () => setCount(current => current + 1)
const dec = () => setCount(current => current - 1)

© 2022 Gabriel Dayley, Kyle West

useEffect

"React" to state changes

useEffect(() => {
  // runs if either values change (including initial)
}, [value, otherValue])

useEffect(() => {
  // runs only once in the life of the component
}, [])

useEffect(() => {
  // handle value here
  return () => { /* fn returned will be ran before the next effect */ }
}, [value])

© 2022 Gabriel Dayley, Kyle West

useRef

Reference data outside of state

const ref = useRef(null) // { current: null }

<input ref={ref} />      // { current: <input> }

ref.current = 3          // { current: 3 }

© 2022 Gabriel Dayley, Kyle West

useMemo

Cache a value for performance

// expensiveFn is called every render
const expensiveResult = expensiveFn(value)
// expensiveFn is only called when the value changes
const memoizedResult = useMemo(() => expensiveFn(value), [value])

© 2022 Gabriel Dayley, Kyle West

useCallback

Cache a function for performance

const handleClick = () => setCount(count + 1)
// harder to read with the function returning a function
const handleClick = useMemo(() => () => setCount(count + 1), [count])
const handleClick = useCallBack(() => setCount(count + 1), [count])

© 2022 Gabriel Dayley, Kyle West

useReducer

Handle complex (or coupled) state

function reducer(state, action) {
  const { count, initialCount } = state
  switch (action.type) {
    case 'inc': return { count: count + 1, initialCount }
    case 'dec': return { count: count - 1, initialCount }
    case 'reset': return { count: state.initialCount, initialCount }
  }
}

// inside of component
const [state, dispatch] = useReducer(reducer, { count: initialCount, initialCount })
const inc = () => dispatch({ type: 'inc' })
const dec = () => dispatch({ type: 'dec' })
const reset = () => dispatch({ type: 'reset' })

© 2022 Gabriel Dayley, Kyle West

💻 Demo Time


© 2022 Gabriel Dayley, Kyle West



Gabe Dayley

@gmdayley

Kyle West

@KyleWestCS


Slides may be found at:

© 2022 Gabriel Dayley, Kyle West

Hello everyone, thank you for coming. My name is Kyle West. This is Gabe Dayley. Today we are going to talk to y'all about hooks. Specifically, we want to visit the internal workings of hooks - by rebuilding them!

These are the hooks we plan on taking a closer look at. But before we do, we just wanted to refresh your memory on what each of these do, and what their API looks like.

The QR code in the corner will take you to the react docs if you are interested. Let's talk about state. - State is information that drives the application - The UI should be a function of the state (i.e., "react" to state changes) - Data is NOT considered state if it: - cannot change during the life of the app - changes, but the UI should not update

useEffect allows us to run arbitrary code when there is a change on a subscribed state

Although references can change their current values, they are not considered state because the UI does not react to data updates.

Memoization is simply the act of caching a value instead of computing a result every time

You could use useMemo to cache a function reference (to attempt creating a stable identity), but instead you can just use the useCallback hook which wraps useMemo

useReducer is like useState, but with a more declarative API in some contexts. It is particularly ideal when multiple state items depend on other state, or needed to be updated in lockstep.

Alright, let's look at some code! TODO: consider adding a code sandbox for people to follow along