Closed tysonzero closed 7 years ago
Hi, I am also interested in this subject, also giving priority to denotational semantics.
I am going to investigate this in the next few days. I plan to post here what I have found.
the short answer: currently, the state is kept until the props change and the component is re-rendered. at that moment, the state is wiped.
a better semantics would be that the stateful component takes a function props -> state -> state
that creates a new initial state on props change from the new props value and the old state.
for now, i think the cleanest solution is to create a new store just for the stateful component, and use that to carry the state value over between re-renderings. this needs some more hacking if you plan to render the component more than once, but if you keep an identifier in the props you could use that to access the part of the store matching a specific rendering. (if anybody could translate this into react-speak i'd be grateful :-)
note that i'm changing my mind again, and getting more optimistic about having multiple store values flying around flux-style. but we haven't investigated that yet.
(and i agree with your bad feeling about referential transparency. haven't digged into it, but see #4.)
right. in fact, it's a duplicate. thanks for spotting it. i'll close this here then.
for now, i think the cleanest solution is to create a new store just for the stateful component, and use that to carry the state value over between re-renderings. this needs some more hacking if you plan to render the component more than once, but if you keep an identifier in the props you could use that to access the part of the store matching a specific rendering. (if anybody could translate this into react-speak i'd be grateful :-)
I mean half the reason I am looking into using stateful components over stores is for the exact purpose of having multiple independent instances of them. I would very very strongly urge against requiring some sort of shared map and having each component keep track of its own key.
Currently in boring old react.js it is very easy to have stateful views that you duplicate and interact with very easily. I was really hoping for no usability decrease with the switch to Haskell, rather the exact opposite with all the powerful language features Haskell has.
Honestly I would much prefer having re-rendering the parent reset the child class states than not being able to have multiple children without a lot of extra effort. Particularly since you can always float up state that you want to persistent through certain re-renders, or you can even put them in Stores explicitly.
So to me such a change would be a big downgrade, as it does not give you any new functionality that wasn't already easy to obtain, and severely negatively affects certain existing functionality.
Oh and on a side note if the state is wiped on re-render then it seems very doable to make this referentially transparent if it isn't already. The more difficult situations arise when trying to do any re-render state persistence, at which point we do have to think a lot more about referential transparency and being real careful about any dirty "create an IORef of sorts with unsafePerformIO and just keep referring back to it" as it will almost certainly break referential transparency.
I am probably going to think a ton about this general issue and try and come up with something, as it seems very key to making this library modular and allowing for reusable and decoupled components. I will try and submit some sort of cohesive design about the type signatures and denotational semantics I think will work well, but it actually does seem like a very hard task to get just right.
Several points:
unsafePerformIO
to get rid of effect control, and deepseq
to introduce it in an ad-hoc way. i would like to change that in that we have abstract monadic types in all places where effects play a role, and constraint types to express what those monads can and cannot do. it's plausible to also do that in the event handlers (we had this discussion elsewhere, don't remember).your designs would be very welcome. meanwhile, we're too busy working on an product based on this, but we are also thinking about this a lot. let's see what we can come up with.
Particularly since I am very interested in making local state more powerful and decoupling from Flux, I am curious under what circumstances the view/dom state will be reset. Particularly considering that it needs to be done in a referentially transparent way without violating Haskell's semantics.
Are there any denotational semantics for this resetting? Also I know it uses
unsafePerformIO
internally, is this use actually safe. To me something it seems like it probably doesn't. Something like:Seems to me to potentially violate referential transparency. The second should clearly have two separate internal states, but that would also require the first to do the same, so does it?
I will test this sometime but was curious if this was documented somewhere, some denotational semantics of sorts would be great.