Wails2 系列 06:状态管理与页面组织:页面、组件、Store 的边界
cbowen

适合读者

适合 Wails 前端页面逐渐变厚,组件、请求和状态逻辑开始缠在一起的开发者。

问题场景

前端复杂度不会因为项目是桌面应用就消失。一个页面可能同时处理表格、表单、弹窗、筛选、远程调用、本地状态、加载状态、错误提示和权限判断。

如果所有逻辑都堆在页面组件里,页面会变成另一个版本的“大 App”:既难读,也难拆,还很难复用。

项目观察

当前项目的前端目录能观察到三个常见层次:

  • frontend/src/pages:页面级流程和路由入口。
  • frontend/src/components:可复用或局部业务 UI。
  • frontend/src/store:跨页面共享状态和缓存。

这三个目录不只是分类,更是职责边界。

拆分原则

页面负责流程编排。

页面可以知道当前要展示哪些组件、何时加载数据、用户完成动作后跳到哪里。页面不应该塞满底层 UI 细节和所有状态变更细节。

组件负责局部展示和交互。

组件应该尽量通过 props 接收数据和回调。它可以有局部状态,例如弹窗开关、输入框临时值,但不应该随意知道整个应用的数据流。

Store 负责跨页面状态。

如果某个状态会被多个页面使用,或者需要缓存、刷新、统一更新,就适合进入 store。比如应用信息、主题、用户资料、待办列表。

改造示例

一个过厚页面可能长这样:

1
2
3
4
5
6
7
8
9
10
function TodoPage() {
// 列表状态
// 表单状态
// 弹窗状态
// 调用 wailsjs
// 过滤排序
// 表格列定义
// 错误提示
// 几百行 JSX
}

可以拆成三层:

1
2
3
4
5
pages/TodoPage.tsx
components/todo/TodoTable.tsx
components/todo/TodoEditor.tsx
store/todoStore.ts
services/api/todo.ts

页面只做编排:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function TodoPage() {
const { items, loading, refresh, create } = useTodoStore()

useEffect(() => {
refresh()
}, [refresh])

return (
<>
<TodoEditor onSubmit={create} />
<TodoTable items={items} loading={loading} />
</>
)
}

store 处理状态:

1
2
3
4
5
6
7
8
9
export const useTodoStore = create((set) => ({
items: [],
loading: false,
refresh: async () => {
set({ loading: true })
const items = await listTodayTodos()
set({ items, loading: false })
},
}))

组件只负责展示和局部交互。

检查清单

  • 页面文件是否明显过长?
  • 页面是否同时承担请求、状态、表格列、弹窗和底层 UI?
  • 可复用 UI 是否被拆进 components?
  • 跨页面状态是否集中在 store?
  • store 是否通过 API 层调用后端,而不是直接依赖生成绑定?
  • 组件是否能通过 props 理解,而不是依赖全局隐式状态?
  • 新增一个页面时,是否能复用已有 store 或组件?

下一篇

下一篇会看 Wails runtime。窗口、事件、剪贴板和通知这些能力也需要统一入口,否则会在前后端两边散开。

 评论
评论插件加载失败
正在加载评论插件