
In this blog post, we will learn what is memoization, how to use it in JavaScript and React, and how it can help us optimize our applications.
What is memoization?
Memoization is an optimization technique that can improve the performance of functions that perform heavy or repetitive computations. It does this by caching the results of these computations and returning them from memory when the same inputs are provided, instead of recalculating them every time.
Memoization in JavaScript
JavaScript is a language that supports higher-order functions, which are functions that can take other functions as arguments or return them as outputs. This feature allows us to create memoized functions, which are functions that remember the results of previous invocations and return them from cache when possible.
To implement memoization in JavaScript, we need two things:
A cache object or array that can store the results of previous computations.
A closure, which is a function that can access variables from its outer scope.
Let's see an example of how we can create a memoized function in JavaScript. We will use the classic example of calculating the Fibonacci sequence, which is a series of numbers where each number is the sum of the previous two numbers.
The naive way to implement a function that returns the nth Fibonacci number is to use recursion, like this:
const fib = n => {
if (n <= 1) return 1;
return fib(n - 1) + fib(n - 2);
};
However, this approach is very inefficient, because it recalculates the same values over and over again. For example, if we call fib(5), we will end up calling fib(0) and fib(1) three times each, fib(2) twice, and fib(3) once.
To avoid this unnecessary work, we can use memoization. We can create a cache object that will store the results of previous calls to fib, and check if the value for a given input is already in the cache before calling fib recursively. If it is, we can return it from the cache. If not, we can calculate it, store it in the cache, and return it.
Here is how we can implement a memoized version of fib:
const fib = () => {
// Create a cache object
const cache = {};
// Return a closure that can access the cache
return n => {
// Check if the value for n is in the cache
if (n in cache) {
// Return it from the cache
return cache[n];
} else {
// Calculate it recursively
let result;
if (n <= 1) {
result = 1;
} else {
result = fib(n - 1) + fib(n - 2);
}
// Store it in the cache
cache[n] = result;
// Return it
return result;
}
};
};
Now, if we call fib(5), we will only calculate fib(0), fib(1), fib(2), fib(3), and fib(4) once each, and store their results in the cache. The next time we call fib with any of these inputs, we will return them from the cache without any computation.
This way, we can improve the performance of our function by reducing the number of calculations it has to perform.
Memoization in React
React is a library for building user interfaces with components. Components are functions or classes that take props as inputs and return elements as outputs. React renders these elements to the DOM and updates them when the props change.
However, sometimes rendering or updating components can be expensive, especially if they involve complex calculations or data transformations. To optimize our components, we can use memoization to avoid unnecessary re-rendering or re-computation.
React provides two built-in hooks for memoization: useMemo and useCallback.
useMemo
The useMemo hook lets us memoize the result of a function that depends on some props or state. It takes two arguments: a function that returns the value to memoize, and an array of dependencies that determine when to recompute the value.
The syntax of useMemo is:
const memoizedValue = useMemo(() => computeValue(dependencies), [dependencies]);
The useMemo hook will call the function and return its result on the first render. On subsequent renders, it will check if any of the dependencies have changed. If they have, it will call the function again and return its new result. If they have not, it will return the previous result from the cache.
The useMemo hook can help us optimize our components in two ways:
- Skipping expensive recalculations: If a component has a prop or state that is used to calculate a derived value that is expensive to compute, we can use useMemo to cache that value and only recompute it when the prop or state changes.
- Skipping re-rendering of components: If a component has a child component that takes a prop that is derived from some expensive calculation, we can use useMemo to cache that prop and only pass it to the child component when it changes. This way, we can prevent the child component from re-rendering unnecessarily.
useCallback
The useCallback hook lets us memoize a function that depends on some props or state. It takes two arguments: a function that we want to memoize, and an array of dependencies that determine when to create a new instance of the function.
The syntax of useCallback is:
const memoizedFunction = useCallback(() => doSomething(dependencies), [dependencies]);
The useCallback hook will create a new instance of the function and return it on the first render. On subsequent renders, it will check if any of the dependencies have changed. If they have, it will create a new instance of the function and return it. If they have not, it will return the previous instance from the cache.
The useCallback hook can help us optimize our components in one way:
- Skipping re-rendering of components: If a component has a child component that takes a function as a prop, and that function depends on some props or state of the parent component, we can use useCallback to cache that function and only pass it to the child component when it changes. This way, we can prevent the child component from re-rendering unnecessarily.
What is the difference?
Are you also confused at this point like me and asking the question what is the difference between useMemo and useCallback? Then here is the answer for you.
The values they memoize are different, useMemo stores the result of the computation(function) whereas useCallback stores the function itself. In other words, the useCallback hook stores function instances and are useful when you pass down the functions as prop to avoid re-rendering. Another simplification could be,useCallback remembers function logic and useMemo remembers what the function calculated.
Conclusion
In conclusion, memoization is a powerful programming technique to optimize the performance of functions that perform heavy and repetitive computations. This is done by caching the results of previous computations or function instances. This concept works behind the scene in the two React hooks useMemo and useCallback.
I hope this blog post was informative and helpful for you. Consider hitting the like button and feel free to add any comments or questions.
Thank you for reading and happy coding!



