Hi there,
We have a big app in which we're gradually replacing old stuff with better stuff.
We're currently replacing some mapStateToProps with hooks and reselect.
Would this code break anything in the memoization?
import { createSelector, createStructuredSelector } from 'reselect';
import { get } from 'lodash';
import { useDispatch, useSelector } from 'react-redux';
import { useEffect } from 'react';
const structuredSelector = createStructuredSelector({
data1 : state => get(state,'some.deep.possibly.null.values'),
data2 : state => Object.keys(get(state,'some.deep.possibly.null.values',{})).length
})
export const useSomeReduxData = () => {
const { data1, data2 } = useSelector(structuredSelector);
useEffect(() => {
// fetch the data here somehow
},[//somedeps])
return { data1, data2 };
};
Cheers
Cl茅ment
what is the impact of hooks on reselect
useSelector don't accept props, so it's always get same param - only the whole state - within one frame, thus it won't break the memoization at all.
But if you put an anonymous function as selector, then the memoization won't work because the selector function has changed.
If you want to reuse selector between multiple instances, you should do
const selector = useCallback(state => {
// createSelector with deps
},[...deps])
const { data1, data2 } = useSelector(selector);
I prefer to use connect, because mixup the render function with the establishment of data flow and local state/logic might have bad impact on performance.
IMO
1.hooks are better to provide ability of reusing logical unit with local state across components.
2.common logic reuse and global state management is what rxjs/redux'middleware should handle.
3.global state mapping and performance optimize is what connect & reselect should do.
But you can use useSelector in a Container Component where you establish data flow or create handlers for Presentation Component.
To tell the truth, I don't think hooks is proper for any global state management. It's core value is reusing and composing logic unit with local state.
IMO, this maybe the best practice:
export default React.memo(
connect(....)(ComponentWithLocalStateWhereYouUseHooks)
);
FWIW, I addressed the tradeoffs between hooks and HOCs in my blog post Thoughts on React Hooks, Redux, and Separation of Concerns, and my ReactBoston talk on Hooks, HOCs, and Tradeoffs.
This statement by @TotooriaHyperion isn't quite correct:
But if you put an anonymous function as selector, then the memoization won't work because the selector function has changed.
Memoization is a question of A) if you're using a library like Reselect that does memoization at all, and B) if you are consistently using the same created selector instance each time.
Here's an example:
const selectUsers = state => state.users;
const selectUserId = (state, userId) => userId;
const selectUserNameById = createSelector(
[selectUsers, selectUserId],
(users, userId) => {
const user = users[userId];
return `${user.firstName} ${user.lastName}`;
}
);
function UserListItem({userId}) => {
const userName = useSelector(state => selectUserNameById(state, userId));
// render
}
This should memoize correctly, at least if there was only one instance of UserListItem. If there were multiple instances of UserListItem being shared, then you would need multiple unique instances of selectUserNameById being created.
Hi there, thanks for being thorough and precise, we're nearly 3 months after my first post and we've had time to think about our use of hooks, redux and reselect.
The redux documentation is quite clear on the point you've explained about multiple selectors (basically it's what @markerikson said)
https://react-redux.js.org/next/api/hooks#using-memoizing-selectors
Thanks a lot for your answers !
Most helpful comment
FWIW, I addressed the tradeoffs between hooks and HOCs in my blog post Thoughts on React Hooks, Redux, and Separation of Concerns, and my ReactBoston talk on Hooks, HOCs, and Tradeoffs.
This statement by @TotooriaHyperion isn't quite correct:
Memoization is a question of A) if you're using a library like Reselect that does memoization at all, and B) if you are consistently using the same created selector instance each time.
Here's an example:
This should memoize correctly, at least if there was only one instance of
UserListItem. If there were multiple instances ofUserListItembeing shared, then you would need multiple unique instances ofselectUserNameByIdbeing created.