Skip to Content
指南第一个应用

第一个应用

你的第一个 Ansiq 应用,不应该是最复杂的 showcase,也不应该是一个几乎什么都没展示的 hello world。

一个合适的教学示例应该至少包含:

  • 一个 App
  • 一次消息流转
  • 一段局部状态
  • 一个输入控件
  • 一段可见的 UI 更新

下面这个例子专门是为理解模型准备的。

use ansiq::prelude::*; use ansiq::{run_app, view}; #[derive(Clone, Debug)] enum Message { Submit(String), } #[derive(Default)] struct NotesApp { submitted: String, } impl App for NotesApp { type Message = Message; fn render(&mut self, cx: &mut ViewCtx<'_, Self::Message>) -> Element<Self::Message> { let draft = cx.signal(|| String::new()); let current = draft.get(); view! { <Paragraph text={"Type and press Enter"} /> <Input value={current.clone()} on_change={{ let draft = draft.clone(); move |next| draft.set_if_changed(next) }} on_submit={|next| Some(Message::Submit(next))} /> <Paragraph text={ if self.submitted.is_empty() { "Last submit: (nothing yet)".to_string() } else { format!("Last submit: {}", self.submitted) } } /> } } fn update(&mut self, message: Self::Message, _handle: &RuntimeHandle<Self::Message>) { let Message::Submit(next) = message; self.submitted = next; } } #[tokio::main(flavor = "multi_thread")] async fn main() -> std::io::Result<()> { run_app(NotesApp::default()).await }

先看结构,不要急着记语法

这个例子里有 4 个最重要的角色:

1. App

App 是 Ansiq 应用的根。它拥有两件核心职责:

  • render:描述当前 UI
  • update:处理消息,修改状态

2. render

render 不是“直接画到 terminal 上”,而是返回一棵 Element 树。

也就是说:

  • 你描述 UI 长什么样
  • runtime 再负责布局、渲染、增量更新

3. cx.signal(...)

这一步用来在 render 过程中创建或获取一个稳定的响应式状态句柄。

这里它的作用非常具体:

  • 当前输入框里的草稿值,由 draft 这个局部 signal 持有
  • Inputon_change 只负责修改这个局部 signal
  • 真正提交后的结果,才写入 self.submitted

注意它不是“普通局部变量”,也不是“直接拿来代替 self”的临时技巧。它是 runtime 和组件作用域配合的一部分。

4. update

update 处理消息,把 UI 事件变成应用状态变化。

这个例子里消息很简单:按 Enter 时提交字符串,然后把结果显示到下面。

这个例子到底发生了什么

当你输入并提交时,Ansiq 里大致会走这条链:

  1. Input 捕获键盘输入
  2. on_change 更新 signal
  3. signal 驱动局部 UI 刷新
  4. on_submit 产出 Message::Submit
  5. runtime 把消息送到 update
  6. update 修改 app state
  7. 下一轮 render 使用新的 self.submitted

所以你可以把它理解成:

  • signal 适合处理“当前这一轮交互里的局部状态”
  • update 适合处理 app 级消息与状态变化

为什么这里同时用了 selfsignal

这是很多人第一次看 Ansiq 时最容易困惑的点。

可以先用一个简单规则理解:

  • self.submitted 是 app 的持久业务状态
  • draft signal 是当前输入框的局部响应式状态

这个例子里,输入框的内容在“按下 Enter 之前”其实没有必要进入 app 的持久状态。
所以让它留在 signal 里,会比“先塞进 self,再从 self 回读到 signal”更自然。

如果后面你的应用需要:

  • update 里验证输入
  • 在多个组件之间共享当前草稿
  • 或者在重启后恢复它

那时再把它提升成 app 级状态也不迟。

下一步该学什么

如果你只会照抄这个例子,还不够。
下一步要理解的是:为什么 Ansiq 要做成 runtime-first,而不是只提供 widgets。

继续阅读 核心概念

Last updated on