2. Memoizing value with useMemo

Table of contents

No heading

No headings in the article.

This blog is part of a series on understanding difference between memo, useMemo and useCallback. click here to check out more blogs.

if you jumped directly to this blog, this codesandbox contains our progress so far.

to understand this let us create a search feature in our app. add following code to your app accordingly.

let's first setup state for the term that we're going to search. add term state in app component.

// app.tsx
const [term, setTerm] = useState("");

also add handleSearch function that set the task as a term using setTerm

// app.tsx
...
const handleSearch = () => {
  setTerm(task);
};
...

right before the return, we create a filteredTodolist variable that will filter todo-list based on the term value. add console.log inside callback to see how many times it's being rendered.

// app.tsx
const filteredTodolist = todolist.filter((todo: todo) => {
  console.log("filtering");
  return todo.task.tolowercase().includes(term.tolowercase());
});

finally, we need to add a search button that calls handleSearch on click. also remove console.log from task and todolist component.

// app.tsx
<button onclick={handleSearch}>search</button>

now, refresh your app preview, you should be able to see "filtering" twice and followed by rendering of the app component.

after adding search

everything looks good till now, let's try adding a new task for search and see how may rendering and filtering you get:

rendering and filtering

you don't need to be genius to understand that this is bad performance, if you're working on large array of data it gets worse, so how to fix this?

and yes, you got it right, by using usememo.

usememo hook will memoize the result(value) of the function and have some dependencies listen to it.

usememo(() => someprocesshere, [dependencies]);

we need to move our filter inside usememo function, and add todolist and term as a dependencies. also pass filtered list to the todolist component.

// app.tsx
...
const filteredTodolist = usememo(() => {
  return todolist.filter((todo: todo) => {
    console.log("filtering");
    return todo.task.tolowercase().includes(term.tolowercase());
  });
}, [todolist, term]);
...

you will able to see filtering won't log all the time:

after adding usememo

now, try searching a new task, here we're searching for task that includes 'co' and then click on search button:

searching 'co' with usememo

rule of thumb with usememo is same as memo just don't use it until it's actually necessary.

Source:

for reference, here is the code we have so far.