kuikly-reactive-observer

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Kuikly 响应式更新与指令系统

Kuikly Reactive Update and Directive System

核心机制

Core Mechanism

attr {}
闭包中读取响应式字段时,框架自动收集依赖;字段值变化时,自动更新绑定的 UI 属性。只需更新数据,UI 自动响应。
注意:
observable
内部使用
==
比较新旧值,相等时不触发更新

When reading reactive fields in the
attr {}
closure, the framework automatically collects dependencies; when the field value changes, the bound UI attributes are updated automatically. Just update the data, and the UI responds automatically.
Note:
observable
uses
==
internally to compare old and new values, no update is triggered when values are equal.

响应式字段声明

Reactive Field Declaration

Pager
(实现了
PagerScope
接口)或任何
PagerScope
子类中使用:
kotlin
// 推荐:PagerScope 扩展函数
import com.tencent.kuikly.core.reactive.handler.observable
import com.tencent.kuikly.core.reactive.handler.observableList
import com.tencent.kuikly.core.reactive.handler.observableSet

var counter by observable(0)                    // 单值
var list by observableList<String>()            // 响应式列表,配合 vfor
var tags by observableSet<String>()             // 响应式集合
Use in
Pager
(which implements the
PagerScope
interface) or any subclass of
PagerScope
:
kotlin
// Recommended: PagerScope extension function
import com.tencent.kuikly.core.reactive.handler.observable
import com.tencent.kuikly.core.reactive.handler.observableList
import com.tencent.kuikly.core.reactive.handler.observableSet

var counter by observable(0)                    // Single value
var list by observableList<String>()            // Reactive list, used with vfor
var tags by observableSet<String>()             // Reactive set

绑定到 UI

Bind to UI

kotlin
var title by observable("Hello")

Text {
    attr {
        text(ctx.title) // 直接引用响应式字段,自动绑定
    }
}
// 更新 ctx.title = "World" 后,Text 自动刷新

kotlin
var title by observable("Hello")

Text {
    attr {
        text(ctx.title) // Directly reference the reactive field, automatic binding
    }
}
// After updating ctx.title = "World", Text refreshes automatically

指令系统

Directive System

循环指令:vfor / vforIndex

Loop Directives: vfor / vforIndex

kotlin
var list by observableList<String>()

// vfor:遍历 observableList,增删时自动增量更新
List {
    attr { flex(1f) }
    vfor({ ctx.list }) { item ->
        Text { attr { text(item) } }
    }
}

// vforIndex:额外提供 index 和 count
vforIndex({ ctx.list }) { item, index, count ->
    View {
        attr { backgroundColor(if (index % 2 == 0) Color.GRAY else Color.TRANSPARENT) }
        Text { attr { text("$index: $item") } }
    }
}
必须传闭包
{ ctx.list }
,不是直接传值
ctx.list
kotlin
var list by observableList<String>()

// vfor: Traverse observableList, automatic incremental update when adding or deleting items
List {
    attr { flex(1f) }
    vfor({ ctx.list }) { item ->
        Text { attr { text(item) } }
    }
}

// vforIndex: Provides additional index and count
vforIndex({ ctx.list }) { item, index, count ->
    View {
        attr { backgroundColor(if (index % 2 == 0) Color.GRAY else Color.TRANSPARENT) }
        Text { attr { text("$index: $item") } }
    }
}
Must pass a closure
{ ctx.list }
, not directly pass the value
ctx.list
.

循环指令:vforLazy(超大列表)

Loop Directive: vforLazy (Large Lists)

仅在
ListView
中使用(不含 PageList、WaterfallList),动态增删可见范围外的虚拟节点:
kotlin
List {
    attr { flex(1f) }
    vforLazy({ ctx.list }, maxLoadItem = 50) { item, index, count ->
        Text { attr { text(item) } }
    }
}
参数类型默认值说明
itemList
() -> ObservableList<T>
数据源闭包
maxLoadItem
Int
30内存中最大虚拟节点数,建议为一屏可见数的 2~3 倍
itemCreator
(T, Int, Int) -> Unit
构建闭包
Only used in
ListView
(excluding PageList, WaterfallList), dynamically adds or removes virtual nodes outside the visible range:
kotlin
List {
    attr { flex(1f) }
    vforLazy({ ctx.list }, maxLoadItem = 50) { item, index, count ->
        Text { attr { text(item) } }
    }
}
ParameterTypeDefault ValueDescription
itemList
() -> ObservableList<T>
Data source closure
maxLoadItem
Int
30Maximum number of virtual nodes in memory, recommended to be 2~3 times the number of visible items on one screen
itemCreator
(T, Int, Int) -> Unit
Builder closure

条件指令:vif / velseif / velse

Conditional Directives: vif / velseif / velse

kotlin
var state by observable(0)

View {
    vif({ ctx.state == 1 }) {
        Text { attr { text("状态1") } }
    }
    velseif({ ctx.state == 2 }) {
        View { attr { size(100f, 100f); backgroundColor(Color.GREEN) } }
    }
    velse {
        Text { attr { text("其他状态") } }
    }
}
velseif
/
velse
必须紧跟
vif
velseif
,中间不能插入其他组件。
kotlin
var state by observable(0)

View {
    vif({ ctx.state == 1 }) {
        Text { attr { text("State 1") } }
    }
    velseif({ ctx.state == 2 }) {
        View { attr { size(100f, 100f); backgroundColor(Color.GREEN) } }
    }
    velse {
        Text { attr { text("Other States") } }
    }
}
velseif
/
velse
must immediately follow
vif
or
velseif
, no other components can be inserted in between.

绑定指令:vbind

Binding Directive: vbind

类似
when
语句,绑定值变化时移除所有子组件并重建
kotlin
var state by observable(0)

View {
    vbind({ ctx.state }) {
        when (ctx.state) {
            1 -> Text { attr { text("状态1") } }
            2 -> View { attr { size(100f, 100f); backgroundColor(Color.GREEN) } }
        }
    }
}
vbind
绑定值为
null
时不执行 creator 闭包。

Similar to the
when
statement, removes all child components and rebuilds them when the bound value changes:
kotlin
var state by observable(0)

View {
    vbind({ ctx.state }) {
        when (ctx.state) {
            1 -> Text { attr { text("State 1") } }
            2 -> View { attr { size(100f, 100f); backgroundColor(Color.GREEN) } }
        }
    }
}
When the bound value of
vbind
is
null
, the creator closure is not executed.

高效更新列表:diffUpdate

Efficient List Updates: diffUpdate

kotlin
// 基本用法(基于 Myers diff 算法,只增删变化的 Item)
list.diffUpdate(newData)

// 自定义比较(通过 id 判断是否同一元素)
userList.diffUpdate(newUsers) { old, new -> old.id == new.id }
方式行为性能
clear() + addAll()
销毁所有 Item → 重建
diffUpdate(newList)
只增删变化的 Item

kotlin
// Basic usage (based on Myers diff algorithm, only adds/deletes changed Items)
list.diffUpdate(newData)

// Custom comparison (judge if it's the same element via id)
userList.diffUpdate(newUsers) { old, new -> old.id == new.id }
MethodBehaviorPerformance
clear() + addAll()
Destroys all Items → RebuildsPoor
diffUpdate(newList)
Only adds/deletes changed ItemsExcellent

常见错误与约束规则

Common Errors and Constraint Rules

详见以下参考文件:
  • 常见错误COMMON_MISTAKES.md — 响应式依赖断开、对象内部属性修改不触发更新、vfor 闭包传值而非传闭包、ViewBuilder 未 invoke 等 8 类典型错误
  • 指令约束规则DIRECTIVE_RULES.md — vfor 闭包必须且仅生成一个根节点、根节点不能是指令节点、vforLazy 仅限 ListView、velseif/velse 必须紧跟 vif、vforIndex 的 index/count 更新规则等

See the following reference documents:
  • Common Errors: COMMON_MISTAKES.md — 8 typical errors including broken reactive dependencies, internal object property modifications not triggering updates, passing values instead of closures in vfor, ViewBuilder not being invoked, etc.
  • Directive Constraint Rules: DIRECTIVE_RULES.md — Rules such as vfor closures must generate exactly one root node, root node cannot be a directive node, vforLazy is limited to ListView, velseif/velse must follow vif immediately, update rules for index/count in vforIndex, etc.