# 状态与数据流

> CrossFly 的状态哲学 —— 无响应式绑定、无 DI，命令式 + 显式失效。

Source: https://crossfly.dev/zh/docs/concepts/state-and-data-flow — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 状态与数据流

对于来自 Flutter、Compose、SwiftUI 或 React 的人来说，这里最令人意外。有两处
刻意的缺失：

- **没有自动的响应式绑定。** 没有 `setState`、可观察对象、`@State` 或重组。改变
  模型**不会**自动更新 UI。
- **没有依赖注入容器。** 没有 Dagger/Guice/Spring。你手动构建并传递你的
  依赖（通常通过屏幕的构造函数）。

## 模型：命令式 + 显式失效
你**读/写模型**、**直接更新组件**，然后框架**重绘**：
```java
model.nome = "Ana";
label.setText(model.nome);   // 大多数 setter 已使布局失效并调用 repaint()
```
大多数组件的 setter 已经替你触发 `repaint()`/使布局失效。需要记住的
唯一规则：

> **改了框架不知道的状态**（你自己的一个计数器、一次计算、一个在
> `onPaint` 中绘制的字段）？**你**来调用 `repaint()`。（参见 [paint thread](/docs/concepts/the-paint-thread)。）

### 经典反例
```java
this.progresso = 0.7f;   // 我改了一个只有我的 onPaint 会读的字段…
// …而界面没变。缺少：
Component.repaint();      // ✔ 现在下一帧会反映新值
```
"我改了状态，屏幕却没更新"几乎总是缺了一个 `repaint()`。

## 为什么这样选择
- **可预测性：** 流程是线性且可见的 —— 数据 → setter → repaint → 帧。没有
  神奇的重组，也没有隐藏的响应式循环需要调试。
- **零魔法，低成本：** 没有响应式依赖图，也没有要配置的 DI 框架。
- 代价是显式性：**管理状态是应用的职责**，而非框架的。

## 框架提供的通信机制
- **回调 / actions** —— `onAction(...)`、通过构造函数传入的回调（参见
  [返回值](/docs/ui/navigation/returning-results)）。
- **父/子层级** —— 遍历组件树。
- **`property(k, v)`** —— 每个组件的"数据袋"（参见 [一切都是 Component](/docs/concepts/everything-is-a-component)）。
- **全局状态** —— 在合理时使用静态字段/共享服务。

## 推荐的范式
由于框架只提供构件，组织范式（每个屏幕一个 **ViewModel/controller** +
用于数据的**仓库**）是应用层的约定 —— 记录于
[best-practices](/docs/best-practices)。框架不强加架构；它提供
组件以及 setter→`repaint()` 这一对。

<div class="cf-diagram">
<svg role="img" id="my-svg" width="874" height="78" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="flowchart" style="max-width: 873.859px; background-color: transparent;" viewBox="0 0.011510848999023438 873.859375 77.97698211669922" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#my-svg{font-family:Manrope,system-ui,sans-serif;font-size:14px;fill:var(--text);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:var(--bg-elev);}#my-svg .error-text{fill:var(--text-dim);stroke:var(--text-dim);}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:var(--text-dim);stroke:var(--text-dim);}#my-svg .marker.cross{stroke:var(--text-dim);}#my-svg svg{font-family:Manrope,system-ui,sans-serif;font-size:14px;}#my-svg p{margin:0;}#my-svg .label{font-family:Manrope,system-ui,sans-serif;color:var(--text);}#my-svg .cluster-label text{fill:var(--text-dim);}#my-svg .cluster-label span{color:var(--text-dim);}#my-svg .cluster-label span p{background-color:transparent;}#my-svg .label text,#my-svg span{fill:var(--text);color:var(--text);}#my-svg .node rect,#my-svg .node circle,#my-svg .node ellipse,#my-svg .node polygon,#my-svg .node path{fill:var(--bg-soft);stroke:var(--border-strong);stroke-width:1px;}#my-svg .rough-node .label text,#my-svg .node .label text,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-anchor:middle;}#my-svg .node .katex path{fill:var(--text-dim);stroke:var(--text-dim);stroke-width:1px;}#my-svg .rough-node .label,#my-svg .node .label,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-align:center;}#my-svg .node.clickable{cursor:pointer;}#my-svg .root .anchor path{fill:var(--text-dim)!important;stroke-width:0;stroke:var(--text-dim);}#my-svg .arrowheadPath{fill:rgba(255, 255, 255, 0);}#my-svg .edgePath .path{stroke:var(--text-dim);stroke-width:1px;}#my-svg .flowchart-link{stroke:var(--text-dim);fill:none;}#my-svg .edgeLabel{background-color:var(--bg-elev);text-align:center;}#my-svg .edgeLabel p{background-color:var(--bg-elev);}#my-svg .edgeLabel rect{opacity:0.5;background-color:var(--bg-elev);fill:var(--bg-elev);}#my-svg .labelBkg{background-color:rgba(255, 255, 255, 0.5);}#my-svg .cluster rect{fill:var(--bg-elev);stroke:hsl(0, 0%, 90%);stroke-width:1px;}#my-svg .cluster text{fill:var(--text-dim);}#my-svg .cluster span{color:var(--text-dim);}#my-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:Manrope,system-ui,sans-serif;font-size:12px;background:var(--bg-elev);border:1px solid hsl(0, 0%, 90%);border-radius:2px;pointer-events:none;z-index:100;}#my-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:var(--text);}#my-svg rect.text{fill:none;stroke-width:0;}#my-svg .icon-shape,#my-svg .image-shape{background-color:var(--bg-elev);text-align:center;}#my-svg .icon-shape p,#my-svg .image-shape p{background-color:var(--bg-elev);padding:2px;}#my-svg .icon-shape .label rect,#my-svg .image-shape .label rect{opacity:0.5;background-color:var(--bg-elev);fill:var(--bg-elev);}#my-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#my-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#my-svg .node .neo-node{stroke:var(--border-strong);}#my-svg [data-look="neo"].node rect,#my-svg [data-look="neo"].cluster rect,#my-svg [data-look="neo"].node polygon{stroke:url(#my-svg-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg [data-look="neo"].swimlane.cluster rect{filter:none;}#my-svg [data-look="neo"].node path{stroke:url(#my-svg-gradient);stroke-width:1px;}#my-svg [data-look="neo"].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg [data-look="neo"].node .neo-line path{stroke:var(--border-strong);filter:none;}#my-svg [data-look="neo"].node circle{stroke:url(#my-svg-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg [data-look="neo"].node circle .state-start{fill:var(--text-dim);}#my-svg [data-look="neo"].icon-shape .icon{fill:url(#my-svg-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg [data-look="neo"].icon-shape .icon-neo path{stroke:url(#my-svg-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg :root{--mermaid-font-family:Manrope,system-ui,sans-serif;}</style><g><marker id="my-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"/></marker><marker id="my-svg_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1, 0;"/></marker><g class="root"><g class="clusters"/><g class="edgePaths"><path d="M131.266,39L137.749,39C144.232,39,157.198,39,169.497,39C181.797,39,193.43,39,199.246,39L205.063,39" id="my-svg-L_Model_VM_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Model_VM_0" data-points="W3sieCI6MTMxLjI2NTYyNSwieSI6Mzl9LHsieCI6MTcwLjE2NDA2MjUsInkiOjM5fSx7IngiOjIwOS4wNjI1LCJ5IjozOX1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M378.063,28.586L391.703,26.905C405.344,25.224,432.625,21.862,459.246,21.985C485.867,22.108,511.827,25.715,524.808,27.519L537.788,29.323" id="my-svg-L_VM_Comp_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_VM_Comp_0" data-points="W3sieCI6Mzc4LjA2MjUsInkiOjI4LjU4NjMyMzUwMTc4NDcwOH0seyJ4Ijo0NTkuOTA2MjUsInkiOjE4LjV9LHsieCI6NTQxLjc1LCJ5IjoyOS44NzMwODY5MDM1NjQwNX1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M673.109,39L681.031,39C688.953,39,704.797,39,719.974,39C735.151,39,749.661,39,756.917,39L764.172,39" id="my-svg-L_Comp_Frame_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Comp_Frame_0" data-points="W3sieCI6NjczLjEwOTM3NSwieSI6Mzl9LHsieCI6NzIwLjY0MDYyNSwieSI6Mzl9LHsieCI6NzY4LjE3MTg3NSwieSI6Mzl9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M541.75,48.127L528.109,50.022C514.469,51.918,487.188,55.709,460.568,56.005C433.948,56.301,407.99,53.102,395.011,51.502L382.032,49.903" id="my-svg-L_Comp_VM_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Comp_VM_0" data-points="W3sieCI6NTQxLjc1LCJ5Ijo0OC4xMjY5MTMwOTY0MzU5NX0seyJ4Ijo0NTkuOTA2MjUsInkiOjU5LjV9LHsieCI6Mzc4LjA2MjUsInkiOjQ5LjQxMzY3NjQ5ODIxNTI5NX1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(170.1640625, 39)"><g class="label" data-id="L_Model_VM_0" transform="translate(-13.8984375, -10.5)"><foreignObject width="27.796875" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>读取</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(459.98908, 18.51151)"><g class="label" data-id="L_VM_Comp_0" transform="translate(-56.84375, -10.5)"><foreignObject width="113.6875" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>setText / setItems</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(720.640625, 39)"><g class="label" data-id="L_Comp_Frame_0" transform="translate(-22.53125, -10.5)"><foreignObject width="45.0625" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>repaint</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(459.98908, 59.48849)"><g class="label" data-id="L_Comp_VM_0" transform="translate(-28.609375, -10.5)"><foreignObject width="57.21875" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>onAction</p></span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="my-svg-flowchart-Model-0" data-look="classic" transform="translate(69.6328125, 39)"><rect class="basic label-container" style="" x="-61.6328125" y="-24.5" width="123.265625" height="49"/><g class="label" style="" transform="translate(-33.6328125, -10.5)"><rect/><foreignObject width="67.265625" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>模型 / 仓库</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-VM-1" data-look="classic" transform="translate(293.5625, 39)"><rect class="basic label-container" style="" x="-84.5" y="-24.5" width="169" height="49"/><g class="label" style="" transform="translate(-56.5, -10.5)"><rect/><foreignObject width="113" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>ViewModel (你的)</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Comp-3" data-look="classic" transform="translate(607.4296875, 39)"><rect class="basic label-container" style="" x="-65.6796875" y="-24.5" width="131.359375" height="49"/><g class="label" style="" transform="translate(-37.6796875, -10.5)"><rect/><foreignObject width="75.359375" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Component</p></span></div></foreignObject></g></g><g class="node default" id="my-svg-flowchart-Frame-5" data-look="classic" transform="translate(817.015625, 39)"><rect class="basic label-container" style="" x="-48.84375" y="-24.5" width="97.6875" height="49"/><g class="label" style="" transform="translate(-20.84375, -10.5)"><rect/><foreignObject width="41.6875" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>下一帧</p></span></div></foreignObject></g></g></g></g></g><defs><filter id="my-svg-drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="var(--text-dim)"/></filter></defs><defs><filter id="my-svg-drop-shadow-small" height="150%" width="150%"><feDropShadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="var(--text-dim)"/></filter></defs><linearGradient id="my-svg-gradient" gradientUnits="objectBoundingBox" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stop-color="var(--border-strong)" stop-opacity="1"/><stop offset="100%" stop-color="hsl(0, 0%, 90%)" stop-opacity="1"/></linearGradient></svg>
</div>

## 参见
- 相关：[paint thread](/docs/concepts/the-paint-thread) · [应用架构（best-practices）](/docs/best-practices)
