-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Idea: wrapping createSelector #606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I'm not convinced there's a serious need to support the use cases of using selectors inside of a reducer. I get that there's some benefit, but given that you're operating on a more limited section of the state, it doesn't seem as useful. |
Yeah, we had that though, too.
createReducer(..., {
case1(state, action) {
const itemBefore = selectById(state, action.payload.id);
adapter.updateOneMutably(state, action.payload);
const itemAfter = selectById(state, action.payload.id);
// one would assume that itemAfter is now different from itemBefore, but since state is still the same object, itemAfter === itemBefore, even if the state would be different
}
});
=> I would suggest definitely doing this for the entityAdapter selectors. The point is: while from an reselect standpoint, shipping a wrapped |
My main worry is that we end up in a situation where we're having to spend a bunch of effort dealing with the wrapping layer for various situations, or people get used to be able to call a selector in one place and then it behaves differently somewhere else. |
I just noticed that Matt pasted an early discussion example - that might not 100% reflect the basic idea. The idea would be to export import {createSelector as createReselectSelector} from 'reselect'
export const createSelector: typeof createReselectSelector = (...args) => {
const selector = createReselectSelector(...args);
return (value, ...rest) => selector(isDraft(value) ? current(value) : value, ...rest)
} So this would affect all our selectors and every selector created by users using our version of Also, this is primarily a hack around the equality check to somehow handle the "same proxy for different contents" problem, so it should not really be "different behavior" from a user's perspective. |
FWIW, I was just bitten by the bug of reselect selectors returning stale data when ran on Immer proxies. Personally, I think the whole point of RTK is to be opinionated – so it should either prevent/warn/heavily discourage using reselect selectors on immer proxies, or it should support it. This silent bug is a really tricky one to catch and I just lost more than an hour trying to track it down. I'm a huge fan of RTK, and this definitely seems like something RTK should have an answer to. It might be worth considering whether its better for performance to use |
@markerikson if I remember correctly, we recently had the same thing come up in another discussion, so people are definitely trying to use these selectors in reducers. So as I'm preparing v1.5, I want to bring this up again: Could we reconsider to either wrap |
I do not want to "transparently wrap I could possibly live with doing it for the generated entity selectors, because those are done internally. On the other hand, the globalized entity selectors aren't usable in a slice anyway because they expect the entire state. |
Fair enough.
I'll open a PR for that.
Well, people seem to create "localized" versions of those 🙈 |
I think this got resolved by the "draftable selector" thingamajig: https://redux-toolkit.js.org/api/createSelector#createdraftsafeselector |
Just wanted to get a log of some ideas here in regards to: immerjs/immer#561 and the original issue it references: #452
@phryneas and I were speaking earlier and brainstormed a few ideas for how this issue could be addressed. Currently, once we bump to v1.4 (or whichever has immer 7.0.1), a user could solve this themselves by doing something like
selectorA(current(state))
inside of a reducer. Being that we use immer everywhere, we could provide a wrapped version ofcreateSelector
and/or entity adapter selectors that does this automatically for a user.Basically, something that would achieve this:
const wrappedEntitySelector = (value) => isDraft(value) ? entitySelector(current(value)) : entitySelector(value)
@phryneas I might've forgotten part of that convo, so please correct me if I'm missing something
The text was updated successfully, but these errors were encountered: