Async data
A Resource exposes its loading and error states as signals alongside the data, so all three bind like anything else. The loader here sleeps instead of calling wasmwrap.Fetch, but the binding code is identical either way.
How it works
The resource
type Post struct {
ID string
Title string
}
posts := reactive.NewResource(func() ([]Post, error) {
return reactive.FetchJSON[[]Post]("/api/posts")
})NewResource runs the loader on its own goroutine and exposes Data, Err and Loading as ordinary signals — you always read the result back through Data.Get().
The status line
reactive.BindText(status, func() string {
if posts.Loading.Get() {
return "Loading…"
}
if err := posts.Err.Get(); err != nil {
return "Error: " + err.Error()
}
return strconv.Itoa(len(posts.Data.Get())) + " posts loaded"
})All three states bind like anything else. The loader here sleeps instead of fetching, but the code is identical either way.
The list
reactive.BindList(list, posts.Data.Get,
func(p Post) string { return p.ID },
func(p Post) wasmwrap.Element {
return wasmwrap.Create("li").SetText(p.Title)
})posts.Data.Get feeds BindList exactly like any other signal — loading, error and data are all the same model.
Reload
reactive.On(reload, "click", func(wasmwrap.Event) { posts.Reload() })Reload re-runs the loader. A generation counter discards a stale response, so an old, slow load can't overwrite newer data.
Full source
type Post struct {
ID string
Title string
}
posts := reactive.NewResource(func() ([]Post, error) {
return reactive.FetchJSON[[]Post]("/api/posts")
})
reactive.BindText(status, func() string {
if posts.Loading.Get() {
return "Loading…"
}
if err := posts.Err.Get(); err != nil {
return "Error: " + err.Error()
}
return strconv.Itoa(len(posts.Data.Get())) + " posts loaded"
})
reactive.BindList(list, posts.Data.Get,
func(p Post) string { return p.ID },
func(p Post) wasmwrap.Element {
return wasmwrap.Create("li").SetText(p.Title)
})
reactive.On(reload, "click", func(wasmwrap.Event) { posts.Reload() })How this demo runs
scripts/demo.go is compiled to demo.wasm by CompileFrom and loaded by WasmScript — see Scripts & WebAssembly. Without WebAssembly the page still renders; only the status stays put.