Jotai?Immer怎么实现undo?redo功能


这篇文章主要介绍了JotaiImmer怎么实现undoredo功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JotaiImmer怎么实现undoredo功能文章都会有所收获,下面我们一起来看看吧。

代码不多,直接上了

import{Patch,applyPatches,produceWithPatches}from"immer";import{atomWithImmer}from"jotai-immer";import{atom,createStore}from"jotai/vanilla";import{JSONSchema7}from"json-schema";interfaceHistoryInfo{patch:Patch;inverse:Patch;}interfaceHistoryState{undo:HistoryInfo[];redo:HistoryInfo[];}//业务代码涉及的undo、redo数据exportinterfaceHistoryItem{businessA:{[key:string]:any};businessB:Record<string,JSONSchema7>;businessC:any;}//构建一个undo、redo的数据起点consthistoryItemAtom=atomWithImmer<HistoryItem>({businessA:{},businessB:{},businessC:{},});//触发需要保存的undo的一个操作事件exportconstfireHistoryAtom=atom(0.0);exportconstbusinessAAtom=atomWithImmer<{[key:string]:any}>({});exportconstbusinessBAtom=atomWithImmer<Record<string,JSONSchema7>>({});exportconstbusinessCAtom=atomWithImmer<any>();exportconsthistoryAtom=atomWithImmer<HistoryState>({undo:[],redo:[],});exportconststore=createStore();//页面数据加载完毕写入初始化historyexportconstdataInit=()=>{constnewHis:HistoryItem={businessA:store.get(businessAAtom),businessB:store.get(businessBAtom),businessC:store.get(businessCAtom),};store.set(historyItemAtom,newHis);};//----------------------------------------------------------------//atomsubscriptionsstore.sub(fireHistoryAtom,()=>{constnewHis:HistoryItem={businessA:store.get(businessAAtom),businessB:store.get(businessBAtom),businessC:store.get(businessCAtom),};constoldHis=store.get(historyItemAtom);const[next,patch,inverse]=produceWithPatches(oldHis,(draft)=>{draft=newHis;returndraft;});store.set(historyItemAtom,next);store.set(historyAtom,(draft)=>{draft.undo.push({patch:patch[0],inverse:inverse[0],});draft.redo=[];});});exportconstfireHistory=()=>{setTimeout(()=>{store.set(fireHistoryAtom,Math.random());},20);};//执行业务代码constdoAction=(item:HistoryItem)=>{store.set(businessAAtom,(draft)=>{draft=item.businessA;returndraft;});store.set(businessBAtom,(draft)=>{draft=item.businessB;returndraft;});store.set(businessCAtom,(draft)=>{draft=item.businessC;returndraft;});store.set(historyItemAtom,(draft)=>{draft=item;returndraft;});};exportconstundoAction=()=>{consthistory=store.get(historyAtom);if(history.undo.length===0){return;}constold=history.undo[history.undo.length-1];constcurrentItem=store.get(historyItemAtom);constitem=applyPatches(currentItem,[old.inverse]);doAction(item);store.set(historyAtom,(draft)=>{constcurrent=draft.undo.pop();if(current){draft.redo.push(current);}});};exportconstredoAction=()=>{consthistory=store.get(historyAtom);if(history.redo.length===0){return;}constold=history.redo[history.redo.length-1];constcurrentItem=store.get(historyItemAtom);constitem=applyPatches(currentItem,[old.patch]);doAction(item);store.set(historyAtom,(draft)=>{constcurrent=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即可

<Providerstore={mainStore}><MainPage/></Provider>

使用方式应该挺简单的吧。 当你做完需要undo的操作后,调用fireHistory()函数即可。页面的undo、redo按钮可以直接把事件映射到undoAction、redoAction。至于undo、redo按钮是否能点的功能可以直接读取 historyAtom 里面undo、redo的数组长度。

关于“JotaiImmer怎么实现undoredo功能”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“JotaiImmer怎么实现undoredo功能”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注主机评测网行业资讯频道。


上一篇:Go的面向对象编程怎么应用

下一篇:Golang中由零值和gob库特性引起BUG怎么解决


Copyright © 2002-2019 测速网 www.inhv.cn 皖ICP备2023010105号
测速城市 测速地区 测速街道 网速测试城市 网速测试地区 网速测试街道
温馨提示:部分文章图片数据来源与网络,仅供参考!版权归原作者所有,如有侵权请联系删除!

热门搜索 城市网站建设 地区网站制作 街道网页设计 大写数字 热点城市 热点地区 热点街道 热点时间 房贷计算器