hexops / vecty

Vecty lets you build responsive and dynamic web frontends in Go using WebAssembly, competing with modern web frameworks like React & VueJS.
BSD 3-Clause "New" or "Revised" License
2.82k stars 144 forks source link

How to make wasm reactive? #276

Closed mar1n3r0 closed 3 years ago

mar1n3r0 commented 3 years ago

The way Go treats wasm as an application means it runs and exits. This is quite limiting compared to modern JS frameworks with their reactive APIs which allow real-time reactivity on external changes. Is this even possible with the current state of things? Maybe keeping dedicated channels open infinite? This would allow all kind of things from state management stores to webhooks to websockets etc.

Go takes a different approach, Go treats this as an application, meaning that you start a Go runtime, it runs, then exits and you can’t interact with it. This, coincidentally, is the error message that you’re seeing, our Go application has completed and cleaned up.

To me this feels more closer to the .NET Console Application than it does to a web application. A web application doesn’t really end, at least, not in the same manner as a process.

And this leads us to a problem, if we want to be able to call stuff, but the runtime want to shut down, what do we do?

https://www.aaron-powell.com/posts/2019-02-06-golang-wasm-3-interacting-with-js-from-go/

Here is an example:

I would like to connect the app to an external state management store and make it re-render on state changes. By the time the state changed the runtime has exited, hence unless there is a channel open to keep it alive it can't react on external events after exit.

pdf commented 3 years ago

Vecty already does this when you call vecty.RenderBody() and friends from your main(), whether the target is WASM or JS.

mar1n3r0 commented 3 years ago

Probably I didn't express the question correctly. How could it react automatically to external changes without manually triggering it?

Maybe keeping dedicated channels opened infinite?

Here is an example:

I would like to connect the app to an external state management store and make it re-render on state changes. By the time the state changed the runtime has exited, hence unless there is a channel open to keep it alive it can't react on external events after exit.

pdf commented 3 years ago

Get your data however (websocket, SSE, etc) and call vecty.Rerender(Component) if you have a handle to the component you want to update.

If you're rendering using the standard Vecty mechanisms, the runtime should not exit. If you're not using Vecty, and are asking about how to do this in a general sense with Go and WASM, try reddit or slack.

mar1n3r0 commented 3 years ago

I don't want to fetch the data manually. I would like to have the app react to an external data source that it is connected to at any point in time when there is external change without explicitly calling manually vecty.Rerender(Component)

I am considering using vecty and the question is vecty specific :)

pdf commented 3 years ago

You absolutely must tell Vecty when to rerender with new data, this is not at odds with your requirements - you receieve data, update some state, and trigger the re-render. That is the workflow.

mar1n3r0 commented 3 years ago

How would you receive data if the rendering life cycle is over and the data is not a DOM event?

Another example:

Let's say we have 2 components with shared state and a state management store. Both components make async 3rd party calls changing different properties of the shared state, the runtime renders and exits. How would you trigger a new run to make the rest of the components depending on shared state be updated?

pdf commented 3 years ago

The runtime never exits - vecty.RenderBody() is a blocking call, vecty.Rerender() triggers a re-render of the existing Component tree below the Component provided as an argument. If you need to receive data from a persistent connection, spawn a goroutine before you call vecty.RenderBody().

There's no official state management solution, so keeping track of which components to update, or implementing more general state management will be up to the author.

I'd recommend taking a look at the example apps for a better understanding of the very basics, then work up to more complex tasks.

VinceJnz commented 3 years ago

The examples I have seen that keep a golang based wasm app running have used a wait-group or open channel. Having said that. vecty has some mechanism to keep it running without explicitly having to use these techniques.

slimsag commented 3 years ago

Looks like this has been answered so I'll close it, feel free to comment and I'll reopen.