I'm using useSelector
hook to retrieve the values of my reducer, but it is causing a lot of unnecessary renders on my application.
It doesn't matter which property I'm using on a component, since they are all getting the same state
object from the reducer, every time one property changes, all components that use useSelector
are rendered.
This is the reducer:
const initialState = {
productsDataState: [], // => this is populated by multiple objects
searchProducts: [],
isSearchOn: false,
inputValue: '',
listOrder: [],
toastify: ['green', ''],
toastifyOpen: false
}
const reducer = ((state = initialState, action) => {
switch (action.type) {
case actionTypes.UPDATE_PRODUCT:
return {
...state,
productsDataState: action.products,
listOrder: action.listOrder
}
case actionTypes.SET_TOASTIFY:
return {
...state,
toastify: action.toastify,
toastifyOpen: action.open
}
case actionTypes.SET_SEARCH:
return {
...state,
searchProducts: action.searchProducts,
isSearchOn: action.isSearchOn,
inputValue: action.inputValue
}
default:
return state
}
})
One of the components is using isSearchOn
, which is a boolean, so I solved the problem checking if the value is true
before rendering it:
const { isSearchOn } = useSelector(state => state.isSearchOn && state)
But that's not the case for all components. The one I'm stuck right now uses the productsDataState
property, which is an array of objects. I can't just make a simple validation before returning state
. I thought about storing the initial value in a useState
, make a deep comparison between the current value and the past one before returning the state, which would work similarly to what I did in the other component, but I can't see how this would be a good approach.
const { productsDataState } = useSelector(state => state)
Is there a way where I could take advantage of useSelector
without comprimising the performance of the application?
I've being reading a lot and making a lot of tests, but I couldn't find a good way to do that so far.
I'd like to keep useSelector
, but I'm open to suggestions, even if it involves other libraries.
CodePudding user response:
What you should be doing is not selecting whole state, just the part you need :)
const productsDataState = useSelector(state => state.productsDataState)
@edit
If you want to select multiple data with one selector you will cause it to change reference if you would try to use an object for example.
const { productsDataState, other } = useSelector(state => ({ productsDataState: state.productsDataState, other: state.other }))
this will cause rerender on any state change as redux use strict equality check by default.
You should listen to official documentation and select each state separately
Call useSelector() multiple times, with each call returning a single field value