跳转到内容

状态和数据流

状态应该尽量靠近使用它的 UI。根据状态渲染,在事件中更新状态。

export function Counter() {
const count = State(0);
return VStack(
Text("Count: " + count),
FilledButton("Increment", {
onPressed: () => count.update((value) => value + 1),
})
).gap(8);
}

State() 返回引用对象。拼接字符串时可以直接使用,需要原始值时使用 .value

使用 .set().update().toggle() 修改局部状态:

const enabled = State(true);
Switch({
value: enabled.value,
onChanged: (value) => enabled.set(value),
});
IconButton({
icon: Icon(enabled.value ? Icons.visibility : Icons.visibility_off),
onPressed: () => enabled.toggle(),
});

状态位于循环、条件分支或共享模型工厂里时,使用 State.key() 提供稳定键。

export function GalleryState() {
const section = State.key("gallery.section", 0);
const dark = State.key("gallery.dark", false);
return {
get section() {
return section.value;
},
get dark() {
return dark.value;
},
selectSection(index) {
section.value = index;
},
toggleTheme() {
dark.toggle();
},
};
}

本地 UI 行为用 JavaScript 回调。需要跨到宿主的工作用 Applet.action()

IconButton({
icon: Icon(Icons.qr_code_scanner),
tooltip: "Scan",
onPressed: Applet.action("scanner.open", { flow: "checkout" }),
});

宿主会收到包含 name 和可序列化 payloadAppletAction

属于 Flutter 的副作用使用宿主动作:

FilledButton("Track purchase", {
onPressed: Applet.action("analytics.track", {
name: "purchase_tap",
source: "checkout",
}),
});

更大的页面可以用模型工厂包装多个 state ref:

export function SettingsState() {
const dark = State.key("settings.dark", false);
const density = State.key("settings.density", "comfortable");
return {
get dark() {
return dark.value;
},
get density() {
return density.value;
},
toggleDark() {
dark.toggle();
},
setDensity(value) {
density.value = value;
},
};
}
export function SettingsScreen(model) {
return ListView([
SwitchListTile({
title: Text("Dark theme"),
value: model.dark,
onChanged: () => model.toggleDark(),
}),
]);
}