5 ms·
Side question: Isn't it grossly inefficient that in Redux, you have reducers that return an entirely new state object? Wouldn't it be better to return some kind
by curiousreacter 8y ago
Side question: Isn't it grossly inefficient that in Redux, you have reducers that return an entirely new state object? Wouldn't it be better to return some kind of data that represents just the diff you intend to make, like {op: INCREMENT, arg: 1, key: "Foo"}?
- kevmo314 8y agoIf just the diffs were returned, you'd need to constantly reapply them to recreate the latest state. By returning the entire state the previous reference can be discarded.
- curiousreacter 8y agoWell, I'm thinking that Redux would apply the diffs to the state destructively, so I'm not sure why we would need to "constantly" reapply them in order to recreate the latest state... we would simply have the latest state on-hand already. But if we're in a context where a lot of rewinding and fast-forwarding of state is happening for some reason, or where these state diffs can't easily be reversed/inverted, then I can see why this would be inefficient.
- RussianCow 8y agoIt depends. If you are making a shallow copy every time via `Object.assign` or the `{...obj}` syntax, then yes, it is rather inefficient. But a) for many (most?) apps it's Good Enough™, and b) you can always use a specialized library like Immutable.js to greatly reduce the overhead. I'm not sure about what would be the benefit of the scheme you are proposing. Are you proposing that the diff then gets applied directly to the state (`state.foo += 1`)? If so, you would remove a powerful assumption that Redux gives you: that a state object will never change from underneath you after being returned from the store. If, instead, you would make a shallow copy of every value affected by the diff, then you haven't gained anything over Redux, and in fact have made the API significantly more complicated for no benefit (aside from maybe slightly less boilerplate for deep paths).
- curiousreacter 8y agoOh right, immutable data structures are good for exactly this situation. I've been in mutation land for a while now. :) However, now I'm newly confused: Yes, I'm proposing that the diff then get applied directly to the state by the Redux infrastructure, and I don't understand why that would break any important assumptions provided by Redux. Is there an example you could give of how this might create a problem?
- RussianCow 8y agoYou would have to be much more disciplined with your approach. With Redux, if I store a reference to any part of the state, I am guaranteed that the value will never be changed by Redux itself (so, unless I manually mutate it, it is guaranteed to be frozen [0]). Because of this, I can do things like safely store a value off of the Redux state inside a component, and when the state changes, I can compare the new value against my stored value to see if it has changed. If you directly mutate state, then the reference would update in-place, so there is no way to compare changes locally without first making a copy. It also goes the other way: I can't accidentally change the state by mutating the object I get back. With your scheme, any "accidental" mutation on any part of the state will actually change the state. This opens up a whole world of bugs, because any time you want to store part of the state locally (inside a component, for instance), you have to remember to make a copy if you want to guarantee that no unwanted side effects occur. (Plus, getting into the convention of "everything is immutable" means you can generally be much more confident about passing objects around without fear of them being mutated unexpectedly.) Edit: Now that I think about it, what you are proposing sounds pretty similar to MobX.[1] You should check it out if you haven't already. I personally strongly prefer Redux for the reasons I mentioned, but it's a pretty solid library either way. [0]: In development, it's very easy to enforce this with Redux by simply calling `Object.freeze` on the state in the root reducer, completely preventing the state object from being mutated. [1]: https://mobx.js.org/ https://mobx.js.org/
- laurent123456 8y agoObjects in JavaScript are references so internally it's just a pointer being passed around.
- curiousreacter 8y agoHmm, but reducers are supposed to return references to new state objects, right? So clearly something more substantial than a pointer has to be created/duplicated.
- jitlerr 8y agoNew object => new pointer.
- chrisco255 8y agoIt's doubtful that state changes are the bottleneck for application performance, for most applications. Rendering and managing the lifecycle of your components usually yields much more tangible perf. gains.
- fouc 8y agoYou might be interested in skipping Redux and just using a state pattern like this http://meiosis.js.org http://meiosis.js.org
- jitlerr 8y agoThat looks awfully complicated.
- fouc 8y agoSorry is that sarcasm? 3 lines of code for a state pattern. Redux is the one that's awfully complicated.
- jitlerr 8y agoSorry, no, it's my honest opinion. I am the kind who is more interested in ideas and patterns than in libraries or frameworks, so I had a look, but this looks like the typical work of a design-disabled programmer. I am not saying that is garbage, but I don't like neither the execution or API design. Redux can be complicated, but Redux is way simpler and easier to reason about than the Meiosis patterns.
- jitlerr 8y ago> Think Redux, MobX, Cerebral, React Context, etc. but without having library imports everywhere and being tied to a framework API. Instead, just plain functions and objects. Undelivered promise.
- sli 8y agoThat is exactly what a Redux action returns. It's a representation of a diff against the current state. At some point though, that diff has to be applied in some form, either atomically (as currently) or through mutation. Actions trigger the reducer that applies the diff to the store. Basically, I'm not certain exactly what you're getting at.