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
Custom Class support in state tree #155
Comments
Any news on this? |
The initiative is great and it is really needed! Immer has (IMO) the cleanest way of writing object updates, but without this, its kind of useless for TS. With that said, what is blocking you? Perhaps some of us could help? |
From my side. I refactored part of my private project on to immer with that fork I linked to and made part of the state work like this. There I encountered two other problems one of which is related. This will not work with Immer as in 'complete' method I will be editing this and not something that came from draft. Editing this there is weird anyways as it kinda is not immutable while we probably want to freeze the object anyways to not allow accident mutations. And getting draft equivalent of this for mutation is tricky. I ended up having pretty weird callbacks/getters chain to the top of the state to open produce transactions, get draft and from it traverse back to 'this' equivalent and make mutations on it. This all made me think of what is good pattern for mutating methods on classes here + that there should be some helper. It seems to me it is wroth collecting some use cases collection to better understand the problem so I chose to continue trying to refactor my mutable class based state to immer and see what patterns I will end up with. On a side note other problem I encountered was that Immer works with trees only. And I ma in bad need for multi parent branches. Aka if we speak about tasks then this is different problem altogether, and I am deep in trying to write a prototype that would allow multi parent nodes and thus this use case |
I guess to get quick results I can make PR that does 3rd thing and does not address 1 and 2 and we can address them later Would be interesting to hear more feedback on those things to see where it is better to go |
Working classes won't really fit the working model of immer for a few reasons
In other words, there are a lot of limitations, really hard to comprehend edge cases when working with classes. Unless classes are basically restrained to be just records or structs. But that kinda defeats the whole purpose as in that case an interface would have sufficed anyways. In other words, using immer should follow from the more fundamental design decision that you want your state to be an immutable, single value tree. If that architectural decision is made, using classes is a quite unlogical / confusing implementation of the design, and should be avoided anyway. Imho. In contrast, when your state is designed to be mutable, using immer (on the mutable parts) is just confusing as well, as it does seem to guarantee things it doesn't really guarantee in such cases. In other words, I think using immer together with classes leads to confusing scenarios at best, and becomes incomprehensible very quickly at worst. @pmilic021 I don't get entirely what you mean when saying immer is unusable with TS? Immer has first class support for TS and strongly typed state tree, which is one of it's main benefits. |
@mweststrate Now I did encounter 3. and solved it in a way I do not like. Now it is 4. that I dug in to. Even if I drop class usage for the state I am still interested in immutable multi-parent graphs. I have a quick implementation that allows tracking multiple parents but it fails some tests for now and I do not have time for last month for side programming sadly but am planning to continue fixing issues with it. But even when done there could be large performance issues with that. Have seen any implementations of immutable graph structures anywhere? ImmutableJS does not do that, neither I found any good examples in other languages. |
Updates the docs a bit to explain why Immer does not support classes |
Could you explain the alternative you're suggesting here? Is there no way to have |
Correct, very simply put, the most trivial pattern like this wouldn't work:
After this, immer should have cloned both an instance of X and an instance of Z, but it is very hard to generalize the concept of cloning for classes, because immer cannot know how the constructor for X should have been called. |
@mweststrate thanks for much for the quick response! That makes sense to me I think. I guess, my question then is, for someone coming from Immutable.js, how can we handle the I see lots of benefits in |
@ianstormtaylor Record doesn't really support having a prototype as well doesn't it? As in; preserving it will being cloned etc (sure you can throw functions in the mix, but that works with immer as well) |
@mweststrate I'm not sure actually. It sounds like I may not be understanding how Given a simple class Point extends Record({
key: null,
offset: null,
path: null,
}) {
get isSet() {
return this.key != null && this.path != null && this.offset != null
}
isInNode(node) {
if (!this.isSet) return false
if (node.object === 'text' && node.key === this.key) return true
if (node.hasNode(this.key)) return true
return false
}
setOffset(offset) {
return this.set('offset', offset)
}
} This example is pulled from my existing Immutable.js
Is this making any sense at all? I might be off the rails 😄 For context, I'm researching this for Slate on account of this discussion. |
This is what ImmutableJS does, it preserves the prototype for object types: We could do the same for immer I guess, but there are some limitations: It has to be clear that constructors should take no args, and it has to be clear on which occassions we should stop recursion (e.g, doing the same trick for Buffer would probably blow up). |
@mweststrate interesting! At least from my own perspective, having the ability to have |
Anyone that cares about class support in Immer, please chime in over here: #202 (comment) |
Tried my hand on it quickly and you can find it here
wonderwhy-er@0fcc078
Issue is that it does not throw on non Date objects now
Also for classes that use private techniques this wont work correctly, probably needs second symbol that allows providing custom proxy that is aware of private state.
Not sure how to proceed so far.
The text was updated successfully, but these errors were encountered: