Reactjs and memoization

React v16.6 and onwards ship with some performance optimizer that can be used to prevent wasteful component re-renders and these optimizers use memoization for that.

memoization

It aims to speed up the application by re-using cached results of expensive function calls to avoid repeating those expensive operations.

Per Wikipedia,

In computing, memoization or memoisation is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again.

Memoization with React.memo

React.memo is a higher-order component(HOC) that renders the same results for the same props. It checks for prop changes in components using shallow comparison. For complex or deeply nested props, a custom comparison function can be passed to achieve the desired results.

// default shallow compare
export default React.memo(MyComp)

// custom compare function
export default React.memo(MyComp, compareFn)

Example:

import React, { useState, useEffect } from "react"

// a sample functional component
function MyComp(props) {
    console.log(`${props.compTitle} got rendered.`)
    return <div>{props.num || "num not passed"}</div>
}

// Memoized version of MyComp
const MemoizedMyComp = React.memo(MyComp)

// component that sets state in 1 sec interval
export default function MemoApp() {
    const [num, setNum] = useState(10)

    useEffect(() => {
        const ci = setInterval(() => {
            setNum(Math.random())
        }, 1000)

        return () => {
            clearInterval(ci)
        }
    }, [])

    return (
        <>
            <MyComp num={11} compTitle={"generic"} />
            <MemoizedMyComp num={11} compTitle={"Memoized"} />
        </>
    )
}

Memoization with useMemo hook

useMemo calculates the value of computing function during render method execution. This calculation is skipped unless dependencies are changed.

const memoizedValue = useMemo(() => computeFn(arguments), [dependencies])

Example:

import React, { useState, useMemo } from "react"

function computeFn(num1, num2) {
    console.log("calculating..")
    for (let index = 0; index < 1000000000; index++) {}
    console.log("calculation done")
    return num1 + num2
}

export default function App() {
    const num1 = 10
    const [num2, setNum] = useState(100)
    const [count, setCount] = useState(100)

    const memoizedValue = useMemo(() => computeFn(num1, num2), [num1, num2])

    const usePreviousValue = () => setNum(100)

    console.log(typeof memoizedValue)

    return (
        <div>
            <div>{memoizedValue}</div>
            <button onClick={() => setNum(Math.random())}>change value</button>
            <button onClick={usePreviousValue}>reset value</button>
            <button onClick={() => setCount(Math.random())}>set count</button>
        </div>
    )
}

Memoization with useCallback hook

useCallback returns a memoized callback. It is similar to useMemo which returns a value instead. functions are created on each render and point to a different reference value. All the child components are re-rendered as there is a change in component prop value.

Example:

function ChildComp() {
    return <button onClick={this.props.callback}>{props.name}</button>
}

const MemoizedComp = React.memo(ChildComp)

function App() {
    const memoizedCallback = useCallback(() => {
        // do something
    }, [a, b])

    return <MemoizedComp callback={memoizedCallback} />
}

More References:

  1. Hooks API Reference in Reactjs docs.