This is a nice approach I've followed myself before. It feels like common sense web development, just writing things in a way which allows them to be reused. A button will likely be the same on any page of the site, so make a button component.
I don't think this is "React-like" though. Making components isn't specific to React. We've been doing that since ASP and probably earlier. Your views still need to know what components to render here.
You can go further and just define a template function which takes a template name and a data object. Then render arbitrary children. That way your UI can be fully composed in code and the only thing your components need to know is how to render themselves.
var templateFS = os.DirFS("./templates/components/")
type Component interface {
Type() string
}
type Button struct {
Name string
}
func (b Button) Type() string {
return "button.html"
}
type Div struct {
Children []Component
}
func (d Div) Type() string {
return "div.html"
}
type Page struct {
Children []Component
}
func (p Page) Type() string {
return "page.html"
}
func main() {
component := Page{
Children: []Component{
Div{
Children: []Component{
Button{Name: "Test button"},
},
},
},
}
templates := template.New("")
funcs := template.FuncMap{
"exec": func(tpl string, data interface{}) template.HTML {
var sb strings.Builder
templates.ExecuteTemplate(&sb, tpl, data)
return template.HTML(sb.String())
},
}
templates = template.Must(templates.Funcs(funcs).ParseFS(templateFS, "*"))
templates.ExecuteTemplate(os.Stdout, component.Type(), component)
Your page.html file becomes
Title
{{range .Children}}
{{exec .Type .}}
{{end}}
For example