Appearance
概览→拆分详解
本节目标:理解“概览→拆分详解”的核心思路,并能把它用于实际开发或面试表达。
一、最重要的内容(概览)
- 单例化
- 不论你在项目中多少次调用
useMarketCalendarStore(),Pinia 只会在第一次调用时执行内部初始化逻辑,后续直接复用同一个实例。
- 不论你在项目中多少次调用
- 模块级 vs Store 内部
- 模块级:所有“全局只需做一次”的工具初始化(如
dayjs.extend)、纯函数、常量,都放在模块顶层。 - Store 内部:所有响应式状态(
ref/reactive)、computed、watch、以及生命周期变量(earliest、registered等),都放在defineStore回调里。
- 模块级:所有“全局只需做一次”的工具初始化(如
- 生命周期步骤
- 模块加载:文件被
import时执行顶层代码(插件注入、defineStore 注册)。 - 首次调用:Pinia 创建并初始化 state、watch、任务调度(
registerTask)、初次计算(recalcAll)。 - 后续调用:直接返回已有实例,不再重复初始化。
- 模块加载:文件被
二、详细拆解
1. 模块加载阶段
- 发生时机:脚本第一次被
import(打包或运行时) - 做了什么:ts
dayjs.extend(utc) dayjs.extend(timezone) const useMarketCalendarStore = defineStore('marketCalendar' /* ↓ 回调未执行 */)- 插件注册:
dayjs时区扩展只做一次; - Store 注册:
defineStore将你的回调函数挂到 Pinia,尚未执行回调内部逻辑。
- 插件注册:
2. 首次调用** **useMarketCalendarStore()
- 发生时机:应用中第一次执行
useMarketCalendarStore() - 做了什么:
- 创建响应式状态:ts
const symbolSessions = ref<Map<string, MarketSession[]>>(new Map()) const holidays = ref<Set<string>>(new Set()) // … 等其它 state、computed、reactive、watch - 挂载 watcher:
- 监听
symbolSessionMap的变化,自动调整下一次调度时间; - 监听
accountStore.selectedAccount,切换账号时可重新拉取节假日。
- 监听
- 注册任务调度:ts
registerTask('__all__', initNow.add(1, 'second'), () => recalcAll(dayjs())) recalcAll(initNow) // 初始化计算一次所有 symbol 的状态 - 设置内部标记:
registered = true,以后不再重复走注册逻辑。 > 注释示例 > > ```ts
- 创建响应式状态:
// 初始化:拉取所有 symbol 状态,并注册定时任务 registerTask('all', initNow.add(1, 'second'), () => recalcAll(dayjs()))
3. 后续再次调用** **useMarketCalendarStore()
- 发生时机:除首次外的所有调用
- 行为:
- Pinia 直接返回已创建好的 store 实例;
- 不会重新执行回调,不会重复创建 state、watch 或 注册任务。
4. 模块级 vs Store 内部的设计取舍
| 内容类别 | 放在模块顶层(module-level) | 放在 defineStore 回调内部 |
| 一次性全局初始化 | dayjs.extend(utc)、工具函数引用、常量 | |
| 纯函数/常量 | getSymbolMarketStatus、toHHMM 等 | |
| 响应式状态 | ref、reactive、computed | |
| 副作用/Watcher | watch(...) | |
| 局部生命周期变量 | earliest、registered、known 等 |
5. 核心流程图(伪代码)
模块加载 → defineStore 注册 首次调用 store → ├─ 创建 state/computed/watch ├─ registerTask → 定时 recalcAll └─ recalcAll 初始化所有 market 状态 后续调用 store → 直接返回实例
通过以上“先概览再拆解”的方式,你可以快速把握 Pinia store 的执行要点,也能清楚地把握哪些逻辑适合放在模块级、哪些必须放到 store 内部。这样一来,既保证了性能(避免重复初始化),又保持了状态管理的清晰与可维护性。
