0

I'm using React with hooks. I have an expensive function that I'd like to memoize.

I know React comes with useMemo(), but the values I need memoized are calculated once, each, on their first render. So there's no point to memoization within the first render, but memoization in future renders would be beneficial.

I've read the useMemo() documentation but it doesn't provide a firm answer So: do the values stored in useMemo() persist across re-renders of the component calling useMemo?

How can I persistently memoize across different renders of a React component?

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
  • sorry your use case is a little bit unclear, can you clarify? useMemo works across rerenders – Giorgi Moniava Apr 09 '21 at 20:56
  • Do different values need to be calculated for *each component instance*, or just once, ever? – CertainPerformance Apr 09 '21 at 20:59
  • @gmoniava I need to calculate a value, it is slow. Subsequent runs of the components function (I'm using hooks not classes) need to access the result of the calculation. – mikemaccana Apr 09 '21 at 21:10
  • @CertainPerformance I don't think hook components have instances - they're just functions that are run, right? – mikemaccana Apr 09 '21 at 21:10
  • Eg if you have `
    `, would you need to run the calculation twice initially, or just once? Or is only one rendered at a given time?
    – CertainPerformance Apr 09 '21 at 21:11
  • @mikemaccana they have instances too – Giorgi Moniava Apr 09 '21 at 21:13
  • @CertainPerformance it's a value that's expensive. I want to run ``, have it calculate that given 1 and 1 the answer is 2. The next time `` runs, and asks for the result for 1 and 2, it gets 2 from a stored value. – mikemaccana Apr 09 '21 at 21:17
  • The next time *the same* instance runs (which `useMemo` will handle), or for *all* instances? Eg with `
    `, calculate once or twice?
    – CertainPerformance Apr 09 '21 at 21:20
  • Sorry @CertainPerformance I don't know what an instance of a function is (do you mean a time the function is invoked?) and there is no expensive component, per my previous comment. Please let me know if there's something specific about that reply I can clarify. – mikemaccana Apr 09 '21 at 21:23
  • A component instance stores the data associated with that particular JSX section. Eg if you have a single ``, and that component gets re-rendered, a few times, like with `useState` setter functions, you still have all the information related to *a single instance* - the one `SomeComponent` being rendered. But if you have ` `, you have *two* instances. – CertainPerformance Apr 09 '21 at 21:27
  • So do you have two instances that you want to share the expensive value, or just one? – CertainPerformance Apr 09 '21 at 21:27
  • OK got it. The component exists once. I do not need to share memoized values between the component instances. Rather I need to share memoized values between a single instance, persisted over different renders. – mikemaccana Apr 09 '21 at 21:29

2 Answers2

1
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

Let's say above line of code is within ComponentA. Now, assuming that ComponentA hasn't been unmounted, then, memoizedValue persists across re renders given also that dependencies (a, b) don't change across re renders.

Also react docs say in the future react may decide to forget the memoized value sometimes so one should use it for optimization not as semantic guarantee.

Giorgi Moniava
  • 27,046
  • 9
  • 53
  • 90
  • I guess the thing that's vague is - **when is a React hook considered 'unmounted'?** Doesn't react simply re-run the components function whenever it needs to? I want to persist the data across different runs of the component. – mikemaccana Apr 09 '21 at 21:09
  • 1
    @mikemaccana Say you render `ComponentA` on one render, and next time you render null instead of it, that is one case when `ComponentA` is considered unmounted. Read more about reconciliation and React lifecycle. – Giorgi Moniava Apr 09 '21 at 21:12
  • Thanks @gmoniava! I have seen the https://reactjs.org/docs/reconciliation.html but the examples only use the class-based components, so I'm not sure how/if it applies to hooks. – mikemaccana Apr 09 '21 at 21:14
  • @mikemaccana it also applies to hooks – Giorgi Moniava Apr 09 '21 at 21:15
  • I guess what I don't understand is - after a render, the hook component's function has returned. How could something stored in `useMemo` still persist after the function has returned? I understand closures, does React use them to keep references to the values stored by `useMemo`? – mikemaccana Apr 09 '21 at 21:21
  • @mikemaccana if you are familiar with state, how does React persist values of state variables in your opinion in hooks between re renders? it has some mechanisms to do that – Giorgi Moniava Apr 09 '21 at 21:22
  • I imagine state is provided to the hook component by the hooks component's arguments for functional purity. However `useMemo()` isn't in the hook components argument so it's a side effect. Which is why I'm confused. – mikemaccana Apr 09 '21 at 21:26
  • @mikemaccana Not sure what you mean, https://reactjs.org/docs/hooks-state.html, you give some value to `useState`, and it persists across re renders. – Giorgi Moniava Apr 09 '21 at 21:30
  • I was (maybe clumsily) making a point about how functional programming avoids the use of side effects by having anything that could mutate state be provided as input, but yes you're right we have `useState()` which (somehow!) provides state to a functional component. I trust `useState()` so I may as well trust `useMemo()`! – mikemaccana Apr 09 '21 at 21:40
0

To do that you need use a way to store the value outside the component by example an Provider and Context. See the React oficial documentation to do that: https://reactjs.org/docs/context.html

My personal recommendation is use Redux for React. Here is your oficial documentation: https://redux.js.org/ This is very used for professional solutions that need store global state or data for your application.

You need to know that the useMemo is always connected to the component lifecycle.