跳到主要内容

Store 观察与反应(速查)

这是一份"5 分钟能用起来"的速查卡片:只需两段关键模板代码,你就能让自己的组件自动响应 store 的变化,或者在数据变化时触发自定义副作用(自动保存、埋点、日志……)。

📚 想深入了解 MobX 追踪规则、所有内置事件、性能优化建议,请看 响应式与事件。本页只做最常见的两件事。


把组件变成"observer":自动响应 store 变化

store 是一个响应式对象。要让 React 组件跟着 store 变化自动刷新,用 mobx-react-liteobserver 包一下:

import { observer } from 'mobx-react-lite';
import { createStore } from '@ydesign/react-editor';

const store = createStore({ key: 'YOUR_API_KEY' });

// 每当 store.objects 变化(新增 / 删除元素),这个组件会自动更新
const ElementsCount = observer(({ store }) => (
<div>当前画布共 {store.objects.length} 个元素</div>
));

核心规则:

  • ✅ 组件里 读了哪个字段,就订阅哪个字段(MobX 按字段追踪)
  • ✅ 只有读到的字段变化时才重新渲染 —— 性能天然友好
  • 不要忘记 observer,否则组件不会更新

要观察当前选中元素?也只需要读 store.selectedElements

const Hint = observer(({ store }) => {
const el = store.selectedElements[0];
if (!el) return <div>请先选中一个元素</div>;
return (
<div>
已选中 {el.type} · 位置 ({Math.round(el.left)}, {Math.round(el.top)})
</div>
);
});

Ydesign 所有内置面板、工具栏都在内部用了 observer,所以你一般只需要给自己写的组件加这个包裹。


监听 store 变化:store.on('change')reaction

不渲染 UI,只在数据变化时执行副作用(自动保存、埋点、同步后台……)?有两种方式,按场景选。

方式 A:最省心 —— store.on('change')

针对"画布对象"整体变化(新增 / 删除 / 修改)的高层订阅,底层做了深度对比,只在真实变化时触发:

const dispose = store.on('change', (objects) => {
console.log('画布变动:当前共', objects.length, '个元素');

// 典型用法:自动保存
fetch('/api/designs/current', {
method: 'PUT',
body: JSON.stringify(store.toJSON()),
});
});

// 不再需要时取消订阅
dispose();

适用场景:

  • 自动保存
  • 脏标记 / 未保存提示
  • 简单的"有变化就做点什么"

方式 B:任意字段 —— mobx.reaction

只想订阅 某一个具体字段 的变化?用 MobX 的 reaction

import { reaction } from 'mobx';

// 画布尺寸变化时,打印新的尺寸
const dispose = reaction(
() => [store.width, store.height], // 1) 数据源
([width, height]) => { // 2) 副作用
console.log('画布尺寸变为', width, '×', height);
},
);

dispose(); // 不再需要时

reaction 的第一个参数是一个纯读取函数(pure selector),第二个参数在它的返回值变化时被调用。它比 store.on('change') 更精细 —— 不相关的字段变化不会打扰到你。

💡 这两种方式可以同时使用store.on('change') 负责"画布整体有变",reaction 负责"某个具体字段有变"。


在 React 里正确管理订阅

上面两种订阅都返回一个 dispose 函数。在 React 里必须把它放到 useEffect 里,组件卸载时自动取消,否则会造成泄漏和内存增长:

import { useEffect } from 'react';
import { reaction } from 'mobx';
import { observer } from 'mobx-react-lite';

const AutoSave = observer(({ store }) => {
useEffect(() => {
// 1 秒节流的自动保存
const dispose = reaction(
() => store.toJSON(),
(json) => fetch('/api/save', { method: 'PUT', body: JSON.stringify(json) }),
{ delay: 1000 },
);

return dispose; // 👈 组件卸载时自动取消订阅
}, [store]);

return null;
});

同样的道理也适用于 store.on('change', ...)

useEffect(() => {
const dispose = store.on('change', (objects) => {
setDirty(true);
});
return dispose;
}, [store]);

Ydesign 避坑清单

现象原因解决方法
组件不更新忘了 observer 包裹export default observer(MyComp)
reaction 每秒触发几十次、请求被冲垮拖拽 / 输入时 store.objects 高频变化{ delay: 1000 } 节流
组件卸载后还在打 logdispose 没被调用放进 useEffect 的 return
改了字段组件却没反应读取放在 useMemo / useCallback把字段读取直接写在渲染函数体里
store.editor 偶尔是 nullEditor 是 <Workspace /> 挂载时才创建store.editor?.xxx 可选链

再深入?