go-app
go-app copied to clipboard
Can't update value when share value between parent UI and child UI from both side
I have a page which have the parent app.Compo and child app.Compo. Both input value shared same value: Shared.Name.
The expected behaviour is:
when I change child input value, the parent input value should changed automatically.

And when I change parent input value, the child input value also changed automatically too.

But child will not changed when I change the parent value.
Here is the test code. Maybe the way I used is not the correct way.
Thank you in advance!
package main
import (
"log"
"net/http"
"github.com/maxence-charriere/go-app/v9/pkg/app"
)
var (
Shared = &shared{}
)
type shared struct {
Name string
}
type child struct {
app.Compo
}
func (c *child) OnMount(ctx app.Context) {
app.Log(Shared.Name)
}
func (c *child) Render() app.UI {
return app.Div().Body(
app.Text("ChildName:"),
app.Input().Type("text").
Value(Shared.Name).
OnChange(c.ValueTo(&Shared.Name)),
)
}
type parent struct {
app.Compo
Name string
}
var _ app.Mounter = (*parent)(nil)
func (c *parent) OnInit() {
Shared = &shared{
Name: "will update from child",
}
}
func (c *parent) OnMount(ctx app.Context) {
app.Log(Shared.Name)
}
func (c *parent) Render() app.UI {
return app.Div().Body(
app.Div().Body(app.Text("ParentName:"),
app.Input().Type("text").
Value(Shared.Name).
OnChange(c.ValueTo(&Shared.Name))),
app.Div().Style("padding", "5px").Body(&child{}),
)
}
func main() {
app.Route("/", &parent{})
app.RunWhenOnBrowser()
http.Handle("/", &app.Handler{
Name: "Isolate",
Description: "Isolated functionality test",
})
if err := http.ListenAndServe(":8000", nil); err != nil {
log.Fatal(err)
}
}
There will also be no events on the child created when parent changes. There is no magic in go-app. It will just update your parent components, not your child components. If you need to update the child, you need to have to create a reason why it should be updated. That is why there is the state observer construct and If you don't want to use it, you must trigger the update by yourself, like calling update for your children manually.
P.S.: The "OnChange" listens on an event from the DOM and all event Handler will always call "Update" on the component, which will call Render. To limit such updates to cases where they are not needed, I added the "skipUpdate" in one of my PRs last year.
@oderwat Thank you for your detail explain!
If I want to update my child component, can you give a hint? How can I do that?
package main
import (
"log"
"net/http"
"github.com/maxence-charriere/go-app/v10/pkg/app"
)
type parent struct {
app.Compo
name string
}
func (p *parent) OnMount(ctx app.Context) {
ctx.Handle("change-parent-name", p.handleChildNameChange)
}
func (p *parent) handleChildNameChange(ctx app.Context, a app.Action) {
p.name = a.Value.(string)
}
func (p *parent) Render() app.UI {
return app.Div().Body(
app.Div().Body(
app.Text("ParentName:"),
app.Input().
Type("text").
Value(p.name).
OnChange(p.ValueTo(&p.name))),
app.Div().
Style("padding", "5px").
Body(&child{Name: p.name}),
)
}
type child struct {
app.Compo
Name string
}
func (c *child) Render() app.UI {
return app.Div().Body(
app.Text("ChildName:"),
app.Input().Type("text").
Value(c.Name).
OnChange(c.onChange),
)
}
func (c *child) onChange(ctx app.Context, e app.Event) {
value := ctx.JSSrc().Get("value")
ctx.NewActionWithValue("change-parent-name", value)
}
func main() {
app.Route("/", func() app.Composer { return &parent{} })
app.RunWhenOnBrowser()
http.Handle("/", &app.Handler{
Name: "Isolate",
Description: "Isolated functionality test",
})
if err := http.ListenAndServe(":8000", nil); err != nil {
log.Fatal(err)
}
}