Imagine I have some custom hook where I extract some value from context ( some kind of my own store )
// example of state structure
function GlobalComponent(){
const initialState = {
reports: {depositReport: []},
users: [],
}
const [state, dispatch] = useReducer(reducer, initialState)
return <StoreContext.Provider value={{state}}></State.Provider>
}
const useSelector = (callback: (state: State) => State) => {
const { state } = useContext(StoreContext);
return callback(state);
};
and here is example of how I use this hook
function Component() {
const { depositReport } = useSelector(state => state.reports);
}
when I extract depositReport
value from state by example above in Component
, it will rerender each time any property changes in state
object. But how can I optimize useSelector
hook , to rerender component when it used only when particular value state => state.reports
will be changed .
Check example on codesandbox, and you will see that when I change users
property , it rerenders place where I only extract reports.depositReport
but I want optimiza useSelector
hook in way , it will only rerender when I extract value on which change I want to react
2
Answers
It is impossible this way. It uses context which value changes on each render. If that value changes, every children component that use
useContext(StoreContext)
rerenders. There is no way to prevent that.What you can do is to use a third party library like
use-context-selector
or create your own store. It is not that simple as just calling useContextSo based on the provided sandbox, I was able to find two key places where you can reduce unnecessary re-renders:
useSelector
functionUsers
component where you are subscribing to the stateHere are the implemented changes:
Here, the use of
useMemo
will recompute the selected part of the state if either the callback function or the state object changes. This, however, requires that you wrap thecallback
function in auseCallback
hook whenever you call it from your components, hence the updatedUsers
component:The definition of
areArraysEqual
: