5

I have a simple example:

import { useMemo, useState } from "react";
import "./styles.css";

const calc = (n) => (
  Math.random()
)

export default function App() {
  const [n, setN] = useState(1);
  const r = useMemo(() => 
    calc(n)
  , [n])
  return (
    <div className="App">
      <input onChange={e => setN(e.target.value)}/><br/>
      <strong>useMemo: {r}</strong><br/>
    </div>
  );
}

Why for the same dependency n it displays different results in r? AFAIK, it should be memoized…

AntonAL
  • 16,692
  • 21
  • 80
  • 114
  • If below answers are useful, click the upvote button (▲) to the left of it. If any answered your question, click the checkmark (✓) to accept it (once the system allows that). That way others know that you've been (sufficiently) helped. Also see [What should I do when someone answers my question?](https://stackoverflow.com/help/someone-answers) – Ajeet Shah May 01 '21 at 16:07

3 Answers3

5

From docs:

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.

Example:

when n = 1, r becomes 0.1234

now when n = 2, r becomes 0.2345. (dependency was changed so it will recompute)

and again when n = 1, r becomes 0.1930. (dependency was changed so it will recompute)


Hence, useMemo is working as expected. But you may need a different tool to accomplish what you are trying to do (maybe something like a Map / Object). Remember that useMemo is a performance optimization tool (it is not a map of key-value).

Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
1

Because useMemo will call again when dependencies change. When you change input, setN will call so state n will change. Then function in useMemo will call and return a new value for r

Viet
  • 12,133
  • 2
  • 15
  • 21
1
<input onChange={e => setN(e.target.value)}/><br/>

The type of e.target.value is String. You initiate the state with Number 1, which is Number type.

So when you type the same initial value on your keyboard, you are actually getting the value as "1".

Since the "1" !== 1, the setState trigger a change.

If you change,

<input onChange={e => setN(e.target.value)}/><br/>

to

<input onChange={e => setN(Number(e.target.value))}/><br/>

Now try to insert the same value as 1, you will see it is not trigger a component update. But now you should be careful as if you type a non numeric value on keyboard, you will get Null as the return of Number(e.target.value). This will lead to not to update the state,

Calling setState with null no longer triggers an update. This allows you to decide in an updater function if you want to re-render.

Dilshan
  • 2,797
  • 1
  • 8
  • 26