Got an issue where I have an object with multiple values in my state but I only need to listen to one for the change.
Example:
On first re-render I might see something like this.
loading: {
objectone: false,
objecttwo: false,
objectthree: false,
}
On my second re-render I might see the state change to something like this:}
loading: {
objectone: true,
objecttwo: false,
objectthree: false,
}
The state then changes further to update the other two objects to true.
loading: {
objectone: true,
objecttwo: true,
objectthree: true,
}
Each time one of the objects in the loading state changes it causes a re-render in my useSelector.
If I wanted just the information in the first object objectone
. How could I write this in my useSelector so that it doesn't trigger a re-render when the other two objects update?
Things I've tried:
before
const loadingStatus = useSelector(({ loading }) => loading);
after
const loadingStatus = useSelector(({ loading }) => {
return loading.objectone ? true : false;
});
Here is an example, your second selector should work and not re render when objectone is not changed:
const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { createSelector } = Reselect;
const initialState = {
loading: {
objectone: false,
objecttwo: false,
objectthree: false,
},
};
//action types
const CHANGE_LOADING = 'CHANGE_LOADING';
//action creators
const changeLoading = (whatLoading) => ({
type: CHANGE_LOADING,
payload: whatLoading,
});
const reducer = (state, { type, payload }) => {
if (type === CHANGE_LOADING) {
return {
...state,
loading: {
...state.loading,
[payload]: !state.loading[payload],
},
};
}
return state;
};
//selectors
const selectLoading = (state) => state.loading;
const createSelectWhatLoading = (what) =>
createSelector(
[selectLoading],
(loading) => loading[what]
);
//creating store with redux dev tools
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducer,
initialState,
composeEnhancers(
applyMiddleware(() => (next) => (action) =>
next(action)
)
)
);
const Loading = React.memo(function Loading() {
console.log('rendeing loading');
const dispatch = useDispatch();
const selectObjectOne = React.useMemo(
() => createSelectWhatLoading('objectone'),
[]
);
const objectone = useSelector(selectObjectOne);
return (
<div>
<p>objectone is {String(objectone)}</p>
<button
onClick={() => dispatch(changeLoading('objectone'))}
>
Change objectone
</button>
<button
onClick={() =>
dispatch(changeLoading('objecttwo'))
}
>
Change objecttwo
</button>
</div>
);
});
const App = () => {
return <Loading />;
};
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>