:: RAIN_YUXUAN
June 3, 2022

React Hooks Cheatsheet

A introduction to React hooks.

useState

A state is a private property of a component and is fully controlled by the component. When the value of a state changes, the component will be re-rendered.

State value must be changed by the setState function to trigger re-render.

Generally, if setState does not assign a new value, then re-render may not be triggered.

Code Artifact
const [state, setState] = useState(initialState)
setState((prevState) => {
  return getNewState(prevState)
})

useEffect

Allows you to perform side effects in your components, such that the side effects do not interrupt rendering immediately. useEffect can perform similar effects as the lifecycle methods. When the component is first rendered, the callback acts like componentDidMount.

What are the Side Effects

Side effects generally include those which affect rendering, such as fetching data, or directly assigning states before rendering. Anything that affects rendering should be put into a useEffect.

Code Artifact
useEffect(() => {
  fetchData()
  return () => cleanup()
}, [...deps])

Dependencies

The effect function is triggered after every render unless dependencies is provided in the list. Dependencies should include every variable that is used in the effect function so that the function is updated on time. Providing an empty list would make the effect only run once. This can replace componentDidUpdate.

Clean up

If the side effect needs things to be cleaned up (e.g., clear a timer), then you need to return a function for that. This acts the same as componentWillUnmount.

Code Artifact
useEffect(() => {const timer = setTimeout(...); return () => clearTimer(timer) })

useRef

Create a reference for a DOM element. Performs better than document.querySelector.

Code Artifact
export default App = () => {
  const headingRef = useRef() // It does not re-create a new instance when the element re-render.
  headingRef.current.innerText = 'HEADING'

  return <h1 ref={headingRef}>Heading</h1>
}

How to change the "state" without re-rendering?

A useful trick to keep and update a variable without re-rendering is to store the value inside ref.current.

useContext

What is Context

A context is like a global store for variables. Context provides a way to pass data through the component tree without having to pass props down manually at every level.

Code Artifact
// stores/MyContext.js
export default MyContext = React.createContext({...initialValues})
// This is not an appropriate place to assign values, but a good place to define types.

// App.js
import ...

export default App = () => {
  const [initialValues, setValues] = useState(...)
  return (
    <MyContext.Provider
      value={{
        ...initialValues,
        setValues,
      }}
    >
      <Content />
    </MyContext.Provider>
  )
}

// Content.js
import ...

export defualt Content = () => {
  const ctx = useContext(MyContext)
  return <h1>{ctx.value}</h1>
}

useReducer

Why use reducer

useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one (when the state can change in multiple ways).

Code Artifact
const [state, dispatch] = useReducer(reducer, initialArg, init)

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + action.payload }
    case 'decrement':
      return { count: state.count - action.payload }
    default:
      throw new Error()
  }
}

Integrate with Context

Code Artifact
const MyContext = React.createContext({
  state: initialState,
  dispatch: () => void,
})

const reducer = (state, action) => {
  switch (action.type) {
    case 'ACTION_1':
      return getNewState(state, action.payload)
    ...
    default:
      throw new Error(`Unhandled action type: ${action.type}`)
  }
}

export const MyContextProvider = ({ children }) => {
  const [state, dispatch] = React.useReducer(reducer, initialState)

  return (
    <MyContext.Provider value={{ state, dispatch }}>
      {children}
    </MyContext.Provider>
  )
}

// App.js > App()
return <MyContextProvider><App/></MyContextProvider>
// Content.js > Content()
const ctx = useContext(MyContext)
ctx.dispatch({ type, payload })

useMemo

Returns a memorized value. Pass a "create" function and an array of dependencies. useMemo will only recompute the memoized value when one of the dependencies has changed. This optimization helps to avoid expensive calculations on every render.

Code Artifact
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])

useCallback

Return a memoized version of the callback function that only changes if one of the dependencies has changed.

Code Artifact
const fn = useCallback(cb, [...deps])
END_OF_FILE