DevTools
DevTools 用于观察状态变化、回放历史并导出调试数据。
- 核心能力:时间旅行、Patch/Snapshot Diff、数据导出。
- 组成:
@iostore/devtools(核心能力)+@iostore/devtools-react(可视化面板)。 - 接入方式:可直接创建实例,也可通过行为扩展统一纳管。
- 需要定位复杂状态更新来源。
- 需要回放用户操作路径排查问题。
- 需要导出状态轨迹给测试或排障流程。
核心 API(实例创建)
Section titled “核心 API(实例创建)”import { io } from '@iostore/store';import { createIoDevtools } from '@iostore/devtools';
const store = io({ counter: 0, user: { name: 'Ada' } });
const devtools = createIoDevtools(store, { name: 'IO Store', maxHistory: 200, captureSnapshots: 'always', perf: { enabled: true, windowSize: 60 },});React 面板接入
Section titled “React 面板接入”import { IoDevtoolsPanel, IoDevtoolsErrorBoundary } from '@iostore/devtools-react';import '@iostore/devtools-react/styles.css';
export function DevtoolsDock({ devtools }) { return ( <IoDevtoolsErrorBoundary> <IoDevtoolsPanel devtools={devtools} height={420} /> </IoDevtoolsErrorBoundary> );}IoDevtoolsPanel 依赖基础样式文件,建议在应用入口或面板组件处引入:
import '@iostore/devtools-react/styles.css';你可以通过 CSS 变量定制主题:
.io-devtools-panel { --io-devtools-panel-bg: #0b1020; --io-devtools-surface: #111827; --io-devtools-text: #e5e7eb; --io-devtools-muted: #9ca3af; --io-devtools-border: #334155;}交互示例(Todo List)
Section titled “交互示例(Todo List)”Todo List
Based on the example todo list, connected to IO DevTools.
Learn IO
Ship a demo
Devtools
Timeline
Details
Select an entry to inspect diffs.
Live 示例(最小集成)
Section titled “Live 示例(最小集成)”你可以直接触发更新、时间旅行和导出,体验最小化的 DevTools 接入链路。
当前 count:0
历史记录长度:0
最近导出大小:0 chars
import { useState, useSyncExternalStore } from 'react';import { createIoDevtools } from '@iostore/devtools';import { io } from '@iostore/store';import { devtools, withBehaviors } from '@iostore/store/behavior';
const store = io({ count: 0 });const view = withBehaviors(store, [ devtools({ target: store, create: (target) => createIoDevtools(target, { name: 'IO Behavior Live Demo', captureSnapshots: 'always', maxHistory: 80, }), }),]);
function DevtoolsMinimalLiveDemo() { const snapshot = useSyncExternalStore( store.subscribe, store.snapshot, store.snapshot, ); const [exportBytes, setExportBytes] = useState(0);
const dt = view.extensions?.devtools;
return ( <section className="io-live"> <div>当前 count:{snapshot.count}</div> <div>历史记录长度:{dt?.getState().history.length ?? 0}</div> <div>最近导出大小:{exportBytes} chars</div> <div className="io-live__row"> <button type="button" className="io-live__button" onClick={() => store.count.set((n) => n + 1)}> +1 </button> <button type="button" className="io-live__button" onClick={() => dt?.timeTravel.undo()}> undo </button> <button type="button" className="io-live__button" onClick={() => dt?.timeTravel.redo()}> redo </button> <button type="button" className="io-live__button" onClick={() => setExportBytes(dt?.export.json().length ?? 0)} > export json </button> </div> </section> );}
export default DevtoolsMinimalLiveDemo;观察点:withBehaviors(devtools(...)) 能把 DevTools 实例挂到 view.extensions,并统一管理生命周期。
devtools.timeTravel.undo()devtools.timeTravel.redo()devtools.timeTravel.goTo(index)
- Patch diff:来自
update.patches - Snapshot diff:
captureSnapshots: 'always'时可用 - Timeline label:优先显示
update.action,无 action 时回退到 patch 摘要
const json = devtools.export.json();const reduxImportState = devtools.export.reduxDevToolsImport();与行为扩展组合
Section titled “与行为扩展组合”devtools() 行为本身不会增加新的调试能力。
调试能力(时间旅行、Diff、导出、面板数据)来自 createIoDevtools(...) 创建的实例。
它的作用是把这个实例接入 withBehaviors() 体系,获得一致的工程化体验:
- 挂载到
view.extensions.devtools(或自定义key)统一访问 - 跟其他行为(如
persist、schedule)一致地组合 - 在
view.destroy()时自动清理devtools.destroy()
如果你不需要 withBehaviors() 的统一组合和生命周期管理,直接调用 createIoDevtools(store, options) 也完全可以。
import { devtools, withBehaviors } from '@iostore/store/behavior';import { createIoDevtools } from '@iostore/devtools';import { io } from '@iostore/store';
const store = io({ count: 0 });const view = withBehaviors(store, [ devtools({ target: store, create: createIoDevtools }),]);
const dt = view.extensions?.devtools;- 未开启快照却期望完整 Snapshot Diff(需
captureSnapshots: 'always')。 maxHistory过大导致内存占用上升。- 只看面板不看 patch/action 上下文,定位效率低。
- 开发环境默认开启 DevTools,生产环境按需开启。
- 对关键交互补充
update.action,提高时间线可读性。 - 结合性能采样配置(
perf)持续观察高频路径。
- 阅读 更新日志。
- 在 Playground 中体验。