components using useContextSelector have to be wrapped in memo to prevent surplus re-renders
laurencefass opened this issue · 9 comments
components using use-context-selector have to be wrapped in memo to prevent surplus re-renders
demo here:
https://codesandbox.io/s/react-use-context-selector-mn8sv?file=/src/App.js
Is this by design, or is it a bug? I cant see any reason why the updates should occur in the non-memoized component.
This is not the case with Redux as components using useSelector do not have to be wrapped by default.
e.g. https://codesandbox.io/s/rtk-counter-53y5q
Thanks
It's how React works. When a component re-renders, all children re-render.
This is the pattern to avoid memo
.
https://codesandbox.io/s/react-use-context-selector-forked-hp59j?file=/src/App.js
(It's the pattern not only for use-context-selector
but for context in general.)
Thanks for feedback.
May I ask: why do you not conceal the useCallback hook call inside your useContextSelector function so its not a requirement on the consumer? It doesnt work properly without it.
i.e. change from
const counter1 = useContextSelector(
context,
useCallback((state) => state.state.counter1, [])
);
to
// the wrapped function exposed to the package consumer
function useContextSelector_wrapped(context, callback) {
return useContextSelector_existing(context, useCallback(callback, [])
}
to conceal the additional useHook, and then use it as follows to match Redux pattern
const counter1 = useContextSelector_wrapped(context, (state) => state.state.counter1));
I guess my question is why do you expose the additional useHook call to the function consumer?
thanks
Oops, sorry, you don't need stable selectors for this lib.
You can just use inline selectors (= no useCallback).
Apologies but I dont understand that statement. What is inline selector and how do i use it can you include example?
Thanks
Sorry, it just means you can do it as you did.
https://codesandbox.io/s/react-use-context-selector-forked-co6gy?file=/src/App.js
Im confused!
I deleted the first sandbox so cant refer back to it. Whats the difference between the op sandbox and the last one you posted. It appears to be working fine. ?
The OP sandbox is
const App = () => {
const [state, setState] = useState(...)
return (
<Context.Provider ...>
...
</Context.Provider>
)
}
When App re-renders all children re-render.
Again, it has nothing to do with how use-context-selector is implemented.
This is a tricky part of how React works/optimizes re-renders.
Maybe this article helps? https://overreacted.io/before-you-memo/
solved! thanks for your help