The GoScript component system is designed to provide a React-like experience for building web applications in Go. This document outlines the key features and usage patterns of the component system.
Components are the building blocks of a GoScript application. There are two types of components:
- Class-based Components: These implement the
Component
interface and can have lifecycle methods, state, and props. - Functional Components: These are functions that take props and return HTML.
Props are properties passed to components. They can be validated using PropTypes.
Components can maintain internal state that can change over time.
Class-based components can implement lifecycle methods to run code at specific points in a component's lifecycle:
ComponentDidMount
: Called after a component is mountedComponentWillUnmount
: Called before a component is unmountedShouldComponentUpdate
: Called before rendering to determine if the component should update
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
Hooks let you use state and other React features without writing a class.
type MyComponent struct {
goscript.LifecycleComponentBase
// Component-specific fields
}
func NewMyComponent(props goscript.Props) *MyComponent {
// Define prop types
propTypes := goscript.PropTypes{
"name": goscript.PropType{
Type: goscript.ReflectKindString,
Required: true,
},
}
// Create base component
base := goscript.NewBaseComponent(props, propTypes)
// Create component
component := &MyComponent{}
component.LifecycleComponentBase.BaseComponent = *base
return component
}
func (c *MyComponent) Render() string {
name := c.GetProps()["name"].(string)
return goscript.CreateElement("div", nil,
goscript.CreateElement("h1", nil, "Hello, " + name),
)
}
func (c *MyComponent) ComponentDidMount() {
fmt.Println("Component mounted")
}
func (c *MyComponent) ComponentWillUnmount() {
fmt.Println("Component will unmount")
}
func (c *MyComponent) ShouldComponentUpdate(nextProps goscript.Props) bool {
return true
}
func MyFunctionalComponent(props goscript.Props) string {
name, _ := props["name"].(string)
return goscript.CreateElement("div", nil,
goscript.CreateElement("h1", nil, "Hello, " + name),
)
}
// Create a context
themeContext := goscript.WithContext(nil)
themeContext.Set("theme", "light")
// Create a provider
provider := goscript.CreateProvider(themeContext, "theme", "dark")
// Use the provider
html := provider(nil,
goscript.CreateElement("div", nil,
// Create a consumer
goscript.CreateConsumer(themeContext, "theme", func(value interface{}) string {
theme := value.(string)
return goscript.CreateElement("p", nil, "Current theme: " + theme)
})(nil),
),
)
func CounterWithHooks(props goscript.Props, componentID string) string {
// Use state hook
countValue, setCount := goscript.useState(componentID, 0)
count := countValue.(int)
// Use effect hook
goscript.useEffect(componentID, func() func() {
fmt.Println("Effect running")
return func() {
fmt.Println("Effect cleanup")
}
}, []interface{}{count})
return goscript.CreateElement("div", nil,
goscript.CreateElement("p", nil, fmt.Sprintf("Count: %d", count)),
goscript.CreateElement("button",
goscript.Props{"onclick": "increment()"},
"Increment"),
)
}
GoScript supports prop validation similar to React's PropTypes:
propTypes := goscript.PropTypes{
"name": goscript.PropType{
Type: goscript.ReflectKindString,
Required: true,
Validator: func(value interface{}) error {
name := value.(string)
if len(name) < 3 {
return fmt.Errorf("name must be at least 3 characters")
}
return nil
},
},
"age": goscript.PropType{
Type: goscript.ReflectKindInt,
Required: false,
Default: 18,
},
}
GoScript includes a JSX-like parser that can transform JSX-like syntax into Go code:
// JSX-like syntax
<div className="container">
<h1>Hello, {name}</h1>
<p>This is a paragraph</p>
</div>
Gets transformed into:
goscript.CreateElement("div", goscript.Props{"className": "container"},
goscript.CreateElement("h1", nil, "Hello, ", name),
goscript.CreateElement("p", nil, "This is a paragraph"),
)
GoScript components can be easily tested:
func TestMyComponent(t *testing.T) {
component := NewMyComponent(goscript.Props{
"name": "John",
})
html := component.Render()
if !strings.Contains(html, "Hello, John") {
t.Errorf("Expected 'Hello, John' in HTML, got: %s", html)
}
}