-
-
Notifications
You must be signed in to change notification settings - Fork 859
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Why can't drafts have computed properties? #317
Comments
@Krantisinh why are you using immer with VueJS objects? VueJS are designed to be mutable so that they can be tracked by Vue, and Immer is trying to achieve to do exactly the opposite, so using immer on these kind of objects doesn't really add any value? The problem with getters is that they can't be cloned. What should be cloned? The value? But in that case they become 'static'. Or should the descriptor be copied? But in that case the closure of the getter might be wrong, that is, referring to something it was already referring to, there is no way to tell.. |
Note: You can still have computed properties on the prototype of your objects. But you also need to do As @mweststrate says, there's no point in using Immer on Vue objects directly. Perhaps you can provide an example of what you're trying to accomplish, @Krantisinh? |
I think Immer is a valid choice with Vue in some cases. But, I think the issue is with Vue and not Immer, since using Vue is a package deal of Vue modify your objects. |
@mweststrate @aleclarson We have redux to manage state in VueJS app. And We're using immer to do state changes in the reducers. Since the traditional methods of changing values in the state end up mutating the state, we felt immer's produce function is our safe bet to do the state changes inside the reducers. |
If you provide a simplified example via CodeSandbox or similar, we can help you out. |
Thank you all for bringing this up. We are also facing this issue. Here is the sample CodePen to illustrate the problem. There are two stores. The store We never use Using Redux and Vue together is a bit odd combination but data flows in Redux are more explict than that of Vuex and thus we use Redux. Earlier we used Ramda and spread operator to manage our reducers but Immer really helped us write clean reducers especially when TypeScript comes into the picture. (It is also one of the reason that we cannot use Vue.js is doing its job right and same goes for Immer. It is just that when they come together, they don't play well. I wonder if we can have any escape hatch for this. |
Note that reassigning your state is nice from the Redux perspective. But it
does kill the VueJS optimization as it can't observe the fine grained
changes. So I think you kinda end up with the worst of both worlds
performance wise :).
It seems VueJS has no option for state to bail out of recursive reactivity
(MobX has observable.ref for that). However, it seems that you could store
the state outside `state` completely: https://stackoverflow.com/a/45815401.
Although I am not sure if a reassignment would cause a render in that case.
Some other options would be: 1) deepclone the state before passing it into
the reducer. But that would make everything even slower. 2) Store your
state as a closure, so, something along the lines of `this.state = () =>
store1.state`. But I am not familiar enough with Vue to know whether a
closure can be stored in that place and used decently in your rendering.
It’s important to note that you should never replace the original state
object in your actions - the components and the store need to share
reference to the same object in order for mutations to be observed. (
https://vuejs.org/v2/guide/state-management.html)
Technically we could invoke getters during drafting, and threat them from
there on as plain values. But I am not sure this is in all circumstances
the intended behavior. I can easily come up with counter examples where
this would be a bad idea. Especially because it will also depend on where
the getter lives. What if it lives on the prototype? Etc.
…On Wed, Feb 20, 2019 at 9:28 AM Harshal ***@***.***> wrote:
Thank you all for bringing this up. We are also facing this issue. Here is
the sample CodePen to illustrate the problem
<https://codepen.io/mistyharsh/pen/aXMMpL?editors=1011>. There are two
stores. The store store1 doesn't user immer for reducer whereas store2
uses produce function.
We never use immer.produce inside Vue.js components. But at some point,
Vue.js adds getters to the data coming out of Redux store and the problem
happens.
Using Redux and Vue together is a bit odd combination but data flows in
Redux are more explict than that of Vuex and thus we use Redux. Earlier we
used Ramda and spread operator to manage our reducers but *Immer* really
helped us write clean reducers especially when TypeScript comes into the
picture. (It is also one of the reason that we cannot use redux-freeze in
dev mode.)
Vue.js is doing its job right and same goes for Immer. It is just that
when they come together, they don't play well. I wonder if we can have any
escape hatch for this.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#317 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABvGhEiXXru3DKbpZQsSEXQ1RSOU4ap8ks5vPQcygaJpZM4a8823>
.
|
This change also makes it very difficult to integrate with EmberJS because of how Ember sets up setters and getters within its KVO to observe state changes on objects. For example, if I have an immer object and create a computed property (not directly on the immer object) that references a dependent key on the immer object then Ember sets up a getter/setter so that it knows when to recompute that computed property. It's merely shadowing to observe changes, do not do anything to the underlying immer objects value. The ability to opt out the of assertion and to take the value of the getter would resolve this. If I find an alternative, I'll circle back and update but for now I don't see a way out of this other than pinning myself to an older version of immer. |
Pardon my naivety: could getters be skipped rather than cloned? I'm wondering if this is a necessary design choice, or one built for maximum defensiveness that also happens to preclude otherwise workable systems. |
@cainlevy Hmm... Should we add a "strict" mode to Immer (which defaults to false) that throws on getters (and possibly other invariants) when true? Maybe not worth the extra kB? We'll need to figure what a strict mode would protect against specifically so we can gauge the worth properly. |
My impression was that Immer defaults to strict mode and |
For all 4 possible behaviors once could give decent arguments, however, the
current one, although bit confusing, is in line how normal object spread /
object.assign work as well on objects with computed properties. So I think
for that reason it best stays as is.
Op ma 20 mei 2019 23:50 schreef Lance Ivy <notifications@github.com>:
… My impression was that Immer defaults to strict mode and [immerable] =
true was how I disabled that strictness.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#317?email_source=notifications&email_token=AAN4NBE2NNPHCZJDT37B753PWMMJRA5CNFSM4GXTZW32YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODV2FOAY#issuecomment-494163715>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAN4NBGYAVMFK2WZH2BPHQ3PWMMJRANCNFSM4GXTZW3Q>
.
|
First off, thank you so much for writing immer. It's a great tool. Question for you though.
What is the rationale behind throwing an error vs really just behaving like Object.assign? |
This reason for me why I want to use Immer with Vue is that I can send patches of object to the server, not the whole Object. If You have nested structures . Frome the Docu of immer "The generated patches are similar (but not the same) to the RFC-6902 JSON patch standard, except that the......" This makes immer so interesting to work with vue. |
My ugly workaround to get the patches in VUE. : l |
One liner comments on a closed issue don't help anyone, and generally aren't read either. If you want to contribute to the discussion; open a new issue, summarize what arguments have already been brought to the table (in this thread, and several others discussing Vue tracking), and then add your valuable insight. |
Using immer v1.9.0+ with VueJS gives error 'Immer drafts cannot have computed properties'
On further analysis, it looks like -
Vue JS sets getters in all properties used in its components by default.
And when we looked at the source of immer, we found that, below code throws error once it encounters a getter on any prop while making a shallow copy.
Immer is an awesome library and we want to continue using the same, but this issue is blocking us. Could you please explain the rationale behind below change and let us know how we can help to fix this issue ?
The text was updated successfully, but these errors were encountered: