import { createProjectDocument } from "@web-video-editor/domain"; import { observer } from "mobx-react-lite"; import { useEffect, useMemo, useRef, useSyncExternalStore } from "react"; import { ProjectCommandController, createEditorStore } from "../store"; import { ClipViewModel } from "./ClipViewModel"; import "./MobxExperiment.css"; declare global { interface Window { __TASK_10_MOBX__?: { getMobx(): ReturnType; getReduxRevision(): number; }; } } const ClipExperiment = observer(function ClipExperiment({ viewModel, }: { viewModel: ClipViewModel; }) { const renderCount = useRef(0); renderCount.current += 1; const fields = [ { label: "位置 X", max: 1, min: 0, set: viewModel.setX, step: 0.01, value: viewModel.x, }, { label: "位置 Y", max: 1, min: 0, set: viewModel.setY, step: 0.01, value: viewModel.y, }, { label: "缩放", max: 3, min: 0.1, set: viewModel.setScale, step: 0.01, value: viewModel.scale, }, { label: "旋转", max: 180, min: -180, set: viewModel.setRotation, step: 1, value: viewModel.rotationDeg, }, { label: "透明度", max: 1, min: 0, set: viewModel.setOpacity, step: 0.01, value: viewModel.opacity, }, ]; return (
MOBX · ISOLATED VIEWMODEL 属性级响应
CLIP VM
{fields.map((field) => ( ))}
action
{viewModel.actionCount}
reaction
{viewModel.reactionCount}
React render
{renderCount.current}

{viewModel.lastAction} · reaction {viewModel.lastReaction}

); }); export function MobxExperiment() { const viewModel = useMemo(() => new ClipViewModel(), []); const store = useMemo( () => createEditorStore( createProjectDocument({ id: "mobx-comparison", name: "Redux Command 对照", }), ), [], ); const controller = useMemo( () => new ProjectCommandController(store), [store], ); const revision = useSyncExternalStore( store.subscribe, () => store.getState().project.document.revision, ); useEffect(() => { window.__TASK_10_MOBX__ = { getMobx: () => viewModel.snapshot(), getReduxRevision: () => store.getState().project.document.revision, }; return () => { delete window.__TASK_10_MOBX__; viewModel.dispose(); }; }, [store, viewModel]); return (

TASK 10 · STATE MODEL LAB

MobX Clip ViewModel 对照实验

左侧只修改临时 ViewModel;右侧 Redux Project 只接受 Command Bus。两者不共享对象,也不互相写入。

返回编辑器
REDUX · COMMAND BUS 工程级事务
{`controller.execute({
  type: "text.add",
  text: { ...serializableProjectData }
});`}
Project revision
{revision}

调整左侧属性时,此 revision 必须保持不变;只有此按钮能修改对照 Project。

); }