Closed jamesdbrock closed 3 years ago
Use this to prevent a
Hook
component from re-rendering needlessly by memoizing the props for theHook
component.
If a component is re-rendered with new props, it's going to re-render. useMemo
won't stop that. You can use it to prevent other kinds of re-renders, though. For example, if you know a child component re-renders every time you pass it a new reference, even when the value is equal, you can use useMemo
to preserve the initial, equivalent reference for passing down to the child.
React will skip re-rendering the component only if the new props is equal-by-reference to the old props (or primitive and equal-by-value).
This is how React works in JavaScript, but it's not how this PureScript wrapper works. Notice the Eq deps
constraint, which is used to determine whether the new dependency is not equal, causing a recompute the cached value. If you need JS reference equality (think ===
), wrap your dependency in an UnsafeReference
(this is what it's for).
if you know a child component re-renders every time you pass it a new reference, even when the value is equal, you can use
useMemo
to preserve the initial, equivalent reference for passing down to the child.
I think this is what I was trying to say, but you put it better.
What do you mean by “if you know”? We know that it is always true that “a child component re-renders every time you pass it a new reference, even when the value is equal, you can use useMemo
to preserve the initial, equivalent reference for passing down to the child.", right?
Oh, maybe we don't know that. Because React probably assumes that our props object is mutable, so even when we pass the same-by-reference props object again, it might re-render?
Is there a way prevent a child component from re-rendering if the child component’s props are equal-by-value (but possibly not equal-by-reference) to the props from the last render?
If the child component uses one of its props to control side effects. Ideally, if it's written in PS and you don't have tons of re-renders happening this should just work as expected. This is because both parent and child will be worrying about PS value equality (Eq
). There may be some duplicate equality checks which can lead to performance issues in large apps, but that's what UnsafeReference
+ useMemo
+ memo
(the one which uses React's shallow reference equality on props to avoid re-renders) solve. You probably don't want to reach for them unless you're experiencing a performance issue or you're building a library and feel enabling this kind of performance optimization is necessary.
React probably assumes that our props object is mutable
React props are immutable by convention, same as state.
Is there a way prevent a child component from re-rendering if the child component’s props are equal-by-value (but possibly not equal-by-reference) to the props from the last render?
memo
enables this for a components props using shallow ref equality, and you can use useMemo
to preserve those references in the parent using Eq
/value equality. For a single parent/child pair this makes very little difference, but for large lists or app-level values which might cause entire app re-renders (or worse, re-mounts) this can sometimes be useful. Generally, though, you want a library to solve this for you.
This is memo. It's a little awkward to use in PS since these are very JS/non-functional concepts, and it is side effecting for the same reason component creation is.. but sometimes it's what you need.
If this library did have docs, this would all be in an "edge-case performance optimization" section 😅
Okay thank you!
You could also do this if using memo
sounds sketch:
child <- useMemo props \_ -> renderChild props
pure child
-- ^ only rebuilds children when props value equality changes
Is what I wrote true? If so then I think this is the best technique for preventing Hook components from re-rendering and we should explain that.