响应式
组件函数在窗口(或父节点)挂载时运行一次。信号会更新依赖它的文本和属性,而不重建整棵树。
#响应式状态
用 ui.CreateSignal 创建信号。在文本和属性中读取它:ui.Text("Count: ", count())、.Width(width())。事件处理函数会自动批量写入。
func TextExample() *ui.Element {
count, setCount := ui.CreateSignal(0)
return ui.View().Children(
ui.Text(
"Count: ",
count(),
).FontSize(20),
ui.Button().Child("Increment").OnClick(func() { setCount(count() + 1) }),
)
}initial := count() 只是快照。之后需要保持更新时请再次读取信号。也可以把信号当作子节点:ui.Text("Count: ", count) 会保留前缀,只更新数字。
自定义组件接受普通的 int、string 和结构体参数。LineItem(product, quantity()) 会继续订阅 quantity。
#派生状态
用 ui.CreateMemo 从其他信号计算值。
func DerivedExample() *ui.Element {
count, setCount := ui.CreateSignal(0)
doubled := ui.CreateMemo(func() int { return count() * 2 })
return ui.View().Children(
ui.Text("Doubled: ", doubled()),
ui.Button().Child("Increment").OnClick(func() { setCount(count() + 1) }),
)
}#副作用与清理
用 ui.CreateEffect 处理树外的工作,例如订阅或窗口标题。它在挂载后运行,并在读取过的值变化时再次运行。ui.OnCleanup 在下次执行前以及组件卸载时运行。
func EffectExample() *ui.Element {
topic, setTopic := ui.CreateSignal("Inbox")
ui.CreateEffect(func() {
current := topic()
log.Print("Subscribe: ", current)
ui.OnCleanup(func() { log.Print("Unsubscribe: ", current) })
})
return ui.View().Children(
ui.Text("Watching: ", topic()),
ui.Button().Child("Switch topic").OnClick(func() {
if topic() == "Inbox" {
setTopic("Archive")
} else {
setTopic("Inbox")
}
}),
)
}直接更新文本和属性。不要在 effect 里重建界面。
#批量更新
点击处理函数已经会批量写入。在其他地方用 ui.Batch 包住相关写入,让观察者只看到一次结果。ui.Untrack 读取信号但不订阅。在 UI goroutine 上读写信号;后台结果用 ui.Async 或 native.Dispatch 送回。
func BatchedExample() *ui.Element {
first, setFirst := ui.CreateSignal("Ada")
last, setLast := ui.CreateSignal("Lovelace")
ui.CreateEffect(func() { log.Print(first() + " " + last()) })
applyProfile := func() {
ui.Batch(func() {
setFirst("Grace")
setLast("Hopper")
})
}
return ui.View().Children(
ui.Text(first(), " ", last()),
ui.Button().Child("Apply profile").OnClick(applyProfile),
)
}