-
Notifications
You must be signed in to change notification settings - Fork 39
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
Preserve state reference if unchanged and not in transaction #25
Preserve state reference if unchanged and not in transaction #25
Conversation
src/index.js
Outdated
let separated = separateState(state); | ||
return baseReducer(separated.optimist, separated.innerState, action); | ||
} | ||
let nextState = fn(state, action); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should still be separating out the state, I think. otherwise the fn
gets called with a different value depending on whether there is a transaction in progress. My suggestion would be to do:
const separated = separateState(state);
const nextState = fn(separated.innerState, action);
if (nextState === separated.innerState) {
return state;
}
validateState(nextState, action);
return nextState;
Thanks for the feedback @ForbesLindesay . I've made updates in 087cba9 to ensure that the original reducer is called with only the |
And for good measure, added an extra unit test in 1682380 to verify the expected behavior that the original reducer is not passed the state with |
src/index.js
Outdated
let {optimist, innerState} = separateState(state); | ||
if (state) { | ||
let nextState = fn(innerState, action); | ||
if (nextState === innerState && !optimist.length) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there are two new problems here:
- If
optimist.length > 0
we should skip straight to baseReducer, not also runfn
first. - It looks like
fn
is potentially getting called twice here (if it applies a change). Thefn
should only ever be called once per action.
Thanks for the continued feedback. This is addressed in 46b6329. I still get a sense there's some redundancy here with |
I think it's ok that some of the code is sort of duplicated, as long as we're not running potentially costly reducers unnecessarily. |
Thanks @ForbesLindesay . While not entirely relevant to the changes here, considering how the destructuring operates to separate state, an operation which may end up not yielding any changes, the pragmatist in me wonders if it's even worth trying to keep the |
The problem with doing that is that it wouldn't play nicely with other clever reducer additions like an "undo"/"redo" reducer. It's important that we keep all our state in redux's store. Options that could be explored would be having the state always be |
Fixes #22
This pull request seeks to resolve an issue where
redux-optimist
returns a new state reference on every dispatch, regardless of whether the original reducer has in-fact returned a new value.The approach is perhaps not quite as elegant as I'd hope, since it moves logic from what might otherwise be considered part of the
baseReducer
into the return function of the top-leveloptimist
. After banging my head at several attempts trying to incorporate intobaseReducer
while also accommodatingcommitReducer
andrevertReducer
, this is what I landed on.The idea is that if we're not in the middle of a transaction and the original reducer produces a strictly equal value to the previous state, we shouldn't bother to separate state, which is not only potentially costly (in iterating over the spread assignment of
innerState
fromseparateState
) but is the root cause for the new reference being returned (destructuring this way will guaranteeinnerState
is always a new value).I've included a test case which fails in master, and granted you access to edit my branch, in case you'd like to hack away at a refactor while achieving the same intent.