Can you have an array as a dependancy for the useMemo
hook?
I know this would be fine:
const dep1 : string = '1'
const thing = useMemo(()=>{
// stuff
},[dep1])
But what about this?:
const dep2 : string[] = ['1', '2']
const thing2 = useMemo(()=>{
// stuff
},[dep2])
I thought that I read once that objects and arrays will always return false for the equality check, effectively meaning thing2
will never be memoized. However I can't see this in the docs:
https://reactjs.org/docs/hooks-reference.html#usememo
This is a contrived example as dep1
and dep2
are constant variables but imagine they were a prop where the value would change.
This is exactly what the useMemo hook does! It will return a memoized value from the provided function unless one of the values in the dependency array changes.
The React hooks that have dependency arrays are: useEffect. useLayoutEffect. useCallback.
If you want to optimize useMemo you can use object properties in the useMemo dependency array.
I think I was getting confused by React.memo
, from the docs:
By default it will only shallowly compare complex objects in the props object. If you want control over the comparison, you can also provide a custom comparison function as the second argument.
function MyComponent(props) {
/* render using props */
}
function areEqual(prevProps, nextProps) {
/*
return true if passing nextProps to render would return
the same result as passing prevProps to render,
otherwise return false
*/
}
export default React.memo(MyComponent, areEqual);
useMemo
appears to work fine with an array as a dependancy:
https://codesandbox.io/s/mystifying-cori-jr0vi?file=/src/App.js:0-647
import React, { useState, useMemo } from "react";
import "./styles.css";
export default function App() {
console.log("App rendered");
const [st, setStr] = useState("0");
const [arr, setArr] = useState([1]);
const thingToRender = useMemo(() => {
console.log("thingToRender ran");
return `Array length is ${arr.length}`;
}, [arr]);
return (
<div className="App">
<button onClick={() => setStr(`${Math.random()}`)}>Change str</button>
<h1>{st}</h1>
<p>{thingToRender}</p>
<button onClick={() => setArr([...arr, Math.round(Math.random() * 10)])}>
Change arr
</button>
</div>
);
}
However it's worth being aware that it wont work if you map
(or other methods that create a new array):
https://codesandbox.io/s/silent-silence-91j8s?file=/src/App.js
import React, { useState, useMemo } from "react";
import "./styles.css";
export default function App() {
console.log("App rendered");
const [st, setStr] = useState("0");
const [arr, setArr] = useState([1]);
const arr2 = arr.map((item) => item);
const thingToRender = useMemo(() => {
console.log("thingToRender ran");
return `Array length is ${arr2.length}`;
}, [arr2]);
return (
<div className="App">
<button onClick={() => setStr(`${Math.random()}`)}>Change str</button>
<h1>{st}</h1>
<p>{thingToRender}</p>
<button onClick={() => setArr([...arr, Math.round(Math.random() * 10)])}>
Change arr
</button>
</div>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With