The useMemo
hook is a performance optimization in React which leverages "memoization" under the hood. Memoization is essentially an internal caching mechanism that allows functions to avoid re-computing expensive values when receiving the same inputs.
useMemo
has the same function signature as useEffect
and useLayoutEffect
because it also takes a function and optional dependency array as its arguments. Unlike those hooks, however, the value returned by useMemo
is a memoized value.
Note: The React documentation suggests that you implement your logic with useEffect
first to make sure your application works. Then, you can go back and refactor with useMemo
to improve app performance.
// Hook runs whenever the value of 'a' or 'b' change
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
// Receiving input for the first time returns a newly computed value
computeExpensiveValue(1, 2)
// Receiving the same input arguments returns a cached value
computeExpensiveValue
Ryan Harris: [0:00] We'll come into our MapView component here and add a useMemo. Like useEffect, useMemo takes an anonymous function, and then an optional second argument called the dependency array. In this case, when locations or the inputValue in our local state change, we want this hook to run again.
[0:20] Inside the function body, let's add an if statement because we only want to execute this block of code if the locations prop coming in from our pair component has value. We'll say if (locations.length > ).
[0:35] Inside of this conditional, we're going to need to create a data object to pass to our Map component down here and make sure that it's formatted correctly. This is going to involve a lot of iteration and filtering, which is expensive work we want to avoid if possible, and useMemo is going to help us do that.
[0:53] Let's come back up to our useMemo hook. To start, let's use this inputValue we're storing in our local state to filter our locations. Inside the if statement, let's add a new variable called data, const data. Here, we want to filter out the locations that don't include the string the user has put in the search input, so that'll be locations.filter(loc => loc.center.toLowerCase().includes(inputValue.toLowerCase()).
[1:34] In looking at the data, we've discovered that there are duplicates in the list coming in from the API, so we're going to want to create an array of unique names.
[1:43] First, we're going to come up here and say let centers = an empty array. Then, we'll come down here and add another filter, .filter. Again, we're going to take the location, so we'll say if (! Centers.includes(loc.center) then we'll want to push centers.push that value to the array, loc.center. Then, we also want to return the location. In the other case, where centers already includes the name, we'll just want to return false.
[2:23] Lastly, we'll need to take our filtered list and create an array of objects. This array will be passed out into our Map component and used to plot the points on our map. We'll come here and say .map, and, again, we're going to take the location, and for each location, we want to return an object.
[2:42] An object will have three fields -- name, which will be equal to loc.center, coordinates, which will be an array, [loc.location.longitude, loc.location.latitude] . Lastly, we'll add a markerOffset. We'll use the value of 22 here.
[3:06] Now that we've created this array of objects, we're going to want to set it to our local estate so that we can pass it down into our child component. We'll store the value as coordData. If we come down below our Map, we'll say setCoordData, and we'll pass in the data variable which is created. As you can see, we are now plotting the points on our map.
[3:27] In summary, useMemo and useEffect have the same function signature. However, useMemo also serves as a performance optimization. By using memoization internally, it allows functions to avoid doing unnecessary work.