ursi / purescript-elmish

this will have its own name eventually
https://github.com/ursi/purescript-package-set
3 stars 0 forks source link

maybe add: afterUpdate :: forall msg. (HTMLInputElement -> Effect Unit) -> Property msg #12

Open Quelklef opened 2 years ago

Quelklef commented 2 years ago

Maybe add:

afterUpdate :: forall msg. (Node -> Effect Unit) -> Attribute msg

This would allow making any modification to an element to be expressed as an Attribute.

Pros:

Cons:

ursi commented 2 years ago

You know, I think we could have a monad whose only effectual capabilities are reading and writing properties of a javascript object.

Quelklef commented 2 years ago

Probably would be a pain to implement, but it'd work.

It definitely does feel kinda weird to me to have an effect that happens "after render" -- sounds like race conditions waiting to happen. Perhaps worse, it seems to make the view impure: although it would remain a pure function, there's nothing stopping me from making an afterUpdate prop which, say, relies on the current time. Yuck!

Really what I'd like is for afterUpdate to take a Node -> Node, but the DOM API doesn't really support that kinda pure thinking...

Quelklef commented 2 years ago

I think a fair middle ground might be to allow getting+setting in the monad, but no method calls.

I don't think this would perfectly section "safe" from "unsafe" -- there are safe Effects, and there are unsafe gets/sets. But it would probably be pretty close.

ursi commented 2 years ago

Oh, I was not clear enough. My imagined monad would only allow reading and writing to the properties of a single object, which we would make the node. So you could not make something that relies on current time.

Quelklef commented 2 years ago

No, I got that. I was just affirming that I think allowing an Effect update to run "after render" seems dangerous

ursi commented 2 years ago

Useful for attribute-like things that currently aren't Attributes, such as setting the value of an without moving the caret

As we have discussed, this can be achieved with an event listener, since they are effectual. Could you provide another example to motivate this? Also keep in mind afterRender already exists, which can implement this behaviour. It is at the cost of having to identify the node globally, but you do also gain more control over when you want to use it, since it's used in an effectual context (update).

Quelklef commented 2 years ago

keep in mind afterRender already exists, which can implement this behaviour

Kind of. If view were Model -> Writer Msg (Html Msg), then we could have an AfterRender (Effect Unit) variant in our message and tell customAttributeEffect within our view. But since view is Model -> Html Msg, we cannot do this. In other words, an Html Msg has no way to perform an effect "immediately", only after some event (click, etc).

(Alternatively, a performImmediately :: forall msg. (Node -> msg) -> Attribute msg would also work.)

Could you provide another example to motivate this?

I think so. In my Y client, there were some calculations I wanted to do based on the placement of a node on screen. This means I wanted to render the node, check some computed properties, and touch up its positioning or whatever.

To be fair, afterUpdate is probably not the only solution to this. But I'm not sure there's any good solution with the current Elmish infrastructure.