Views

View is the core building block of Matcha. It defines components that come together to create a hierarchy of views that becomes your app.

View

The View interface has the following six methods.

Build(Context) Model

Build is the most important method. It is similar to React’s render() function. When your view updates and needs to be displayed, Build is called to get the view’s children, layout, paint style, options, etc. These are returned in the Model struct. Unlike iOS or Android where properties can be changed independently (label.title = @“Foo”), when a Matcha view updates, Build() is called again and all its properties and children are completely recreated.

ViewKey() interface{}

ViewKey returns a view’s stable identifier. This should not change over the lifetime of the view. This allows Matcha to to track which items have been added or removed.

Lifecycle(from, to Stage)

Lifecycle gets called as a view gets displayed or hidden. A view may cross through multiple lifecycle stages at the same time. For example a view can start at StageDead and jump directly to StageVisible. If the view needs to perform an action on mount, EntersStage(from, to, StageMounted) can be used to track this transition.

Update(View)

Update gets called after a view’s parent’s gets rebuilt and Matcha is able to match an older view with a newer one, see Diffing and Reconciliation. Update will be called on the older view, with the new view passed as a parameter. It should copy all the fields of the new View either manually or using view.CopyFields(dst, src). If the Embed struct is used, CopyFields will be called automatically.

Notify(f func()) comm.Id
Unnotify(id comm.Id)

Finally we have Notify and Unnotify which provide a way for views to signal to the framework that they have changed and need updating. See the comm.Notifier docs for more information.

As a guideline the following is recommended.

* Views should not keep references to their children or modify/create them outside of Build().
* Views should not keep references to their parents.
* Views should only be modified while the matcha.MainLocker() mutex is held.

Embed

Implementing all the View methods for every component would be a hassle, so instead we can use Go’s embedding with the Embed struct to provide a basic implementation of these methods. Embed additionally adds the Subscribe(), Unsubscribe(), and Signal() methods to simplify notifying for updates. We see an example of this below.

type ExampleView struct {
    view.Embed
    notifier comm.Notifier
}
func New(n comm.Notifier) *ExampleView {
    return &ExampleView{
        Embed: view.NewEmbed(n),
        notifier: n,
    }
}
func (v *ExampleView) Lifecycle(from, to view.Stage) {
    if view.EntersStage(from, to, view.StageMounted) {
        // Update anytime v.n changes.
        v.Subscribe(v.notifier)
    } else if view.ExitsStage(from, to, view.StageMounted) {
        // We must unsubscribe when the view is unmounted or risk a leak.
        v.Unsubscribe(v.notifier)
    }
}
func (v *ExampleView) Build(ctx *view.Context) view.Model {
    child := button.New()
    child.String = "Click me"
    child.OnClick = func() {
        // Trigger the view to rebuild when the button is clicked.
        v.Signal()
    }
    return view.Model{
        Children: []view.View{child},
    }
}