您好,登录后才能下订单哦!
这篇文章主要介绍了Jotai Immer怎么实现undo redo功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Jotai Immer怎么实现undo redo功能文章都会有所收获,下面我们一起来看看吧。
import { Patch, applyPatches, produceWithPatches } from "immer"; import { atomWithImmer } from "jotai-immer"; import { atom, createStore } from "jotai/vanilla"; import { JSONSchema7 } from "json-schema"; interface HistoryInfo { patch: Patch; inverse: Patch; } interface HistoryState { undo: HistoryInfo[]; redo: HistoryInfo[]; } // 业务代码涉及的undo、redo数据 export interface HistoryItem { businessA: { [key: string]: any }; businessB: Record<string, JSONSchema7>; businessC: any; } // 构建一个undo、redo的数据起点 const historyItemAtom = atomWithImmer<HistoryItem>({ businessA: {}, businessB: {}, businessC: {}, }); // 触发需要保存的undo的一个操作事件 export const fireHistoryAtom = atom(0.0); export const businessAAtom = atomWithImmer<{ [key: string]: any }>({}); export const businessBAtom = atomWithImmer<Record<string, JSONSchema7>>({}); export const businessCAtom = atomWithImmer<any>(); export const historyAtom = atomWithImmer<HistoryState>({ undo: [], redo: [], }); export const store = createStore(); // 页面数据加载完毕写入初始化history export const dataInit = () => { const newHis: HistoryItem = { businessA: store.get(businessAAtom), businessB: store.get(businessBAtom), businessC: store.get(businessCAtom), }; store.set(historyItemAtom, newHis); }; // ---------------------------------------------------------------- // atom subscriptions store.sub(fireHistoryAtom, () => { const newHis: HistoryItem = { businessA: store.get(businessAAtom), businessB: store.get(businessBAtom), businessC: store.get(businessCAtom), }; const oldHis = store.get(historyItemAtom); const [next, patch, inverse] = produceWithPatches(oldHis, (draft) => { draft = newHis; return draft; }); store.set(historyItemAtom, next); store.set(historyAtom, (draft) => { draft.undo.push({ patch: patch[0], inverse: inverse[0], }); draft.redo = []; }); }); export const fireHistory = () => { setTimeout(() => { store.set(fireHistoryAtom, Math.random()); }, 20); }; // 执行业务代码 const doAction = (item: HistoryItem) => { store.set(businessAAtom, (draft) => { draft = item.businessA; return draft; }); store.set(businessBAtom, (draft) => { draft = item.businessB; return draft; }); store.set(businessCAtom, (draft) => { draft = item.businessC; return draft; }); store.set(historyItemAtom, (draft) => { draft = item; return draft; }); }; export const undoAction = () => { const history = store.get(historyAtom); if (history.undo.length === 0) { return; } const old = history.undo[history.undo.length - 1]; const currentItem = store.get(historyItemAtom); const item = applyPatches(currentItem, [old.inverse]); doAction(item); store.set(historyAtom, (draft) => { const current = draft.undo.pop(); if (current) { draft.redo.push(current); } }); }; export const redoAction = () => { const history = store.get(historyAtom); if (history.redo.length === 0) { return; } const old = history.redo[history.redo.length - 1]; const currentItem = store.get(historyItemAtom); const item = applyPatches(currentItem, [old.patch]); doAction(item); store.set(historyAtom, (draft) => { const current = draft.redo.pop(); if (current) { draft.undo.push(current); } }); };
定义 HistoryItem 作为undo、redo所需要恢复的业务数据,可随意扩展。undo、redo本质上就是你点了undo按钮后你的数据需要恢复到上一个状态。当业务复杂了之后,你一次操作可能包含了多个数据的变化,而你undo的操作应该是把这些数据一起还原。所以把涉及到变化的数据都包装在一起,形成一个historyitem。通过 immer提供的produceWithPatches生成撤销和恢复数据, 存在 HistoryState 的undo 里,然后你点击undo按钮,把数据从undo中取出,放入redo中。然后把数据状态通过jotai全局修改,差不多就完成了。
简单的jotai使用是不需要store参与的,这里为了取数据、改数据方便,所以使用了store的监听和set功能。 使用store的代码也很简单,直接在最外层包个provider即可
<Provider store={mainStore}> <MainPage /> </Provider>
使用方式应该挺简单的吧。 当你做完需要undo的操作后,调用fireHistory()函数即可。页面的undo、redo按钮可以直接把事件映射到undoAction、redoAction。至于undo、redo按钮是否能点的功能可以直接读取 historyAtom 里面undo、redo的数组长度。
关于“Jotai Immer怎么实现undo redo功能”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Jotai Immer怎么实现undo redo功能”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。