React Cheatsheet | 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.

JavaScript
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.

JavaScript
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.

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

useRef

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

JavaScript
export default App = () => {
    const headingRef = useRef()   // It does not re-create a new instance when the element re-render.
    headingRef.<strong>current</strong>.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.

JavaScript
// 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). 

JavaScript
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

JavaScript
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.

JavaScript
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.

JavaScript
const fn = useCallback(cb, [...deps])
,