Often times you'll want the user of your application to be able to undo an action that they've taken. Adding this feature requires you to keep track of the actions that have occurred and what state the application was in at each action.
To solve this, you'll need to store the history in some way. With Jotai, because the atoms that you are using are immutable you can save a snapshot of an atom when an action is taken and store that for use later on.
We will replace the previous shapesAtomsAtom
that stored the array of our svg shapes with a historyAtom
that will add each snapshot of the canvas to an array. We can then export a new shapesAtomsAtom
that will behave exactly like the previous one as well as a saveHistoryAtom
that we can use when we update our state. This will allow implementing an undoHistory
atom that will remove any shapes or colors that we don't want to use on our canvas.
Daishi Kato: [0:00] We define ShapeAtomValue and ShapeAtom's types. ShapeAtomValue is an immutable object, and we can safety store it in history. In the new history.ts file, we define internalShapeAtomsAtom and historyAtom. Both are primitive atoms and not exported.
[0:22] Next is to create saveHistoryAtom. It will read internalShapeAtomsAtom and create an immutable snapshot array and add it into the beginning of the historyAtom. Then, create shapeAtomsAtom, which behaves exactly like a primitive atom, but it saves history before updating internalShapeAtomsAtom.
[0:47] Lastly, we define undoAtom. It returns hasHistory as its value for disabling button. On write, it will restore internalShapeAtomsAtom with the first item in the historyAtom. In SvgShapes.tsx, all we need is to replace shapeAtomsAtom with the one defined in history.ts.
[1:09] Finally, in Controls.tsx, we import undo atom and define the Undo button. The button is disabled when there is no history. Let's try how it works. See? It's working well.
[1:24] Now, what we want to undo, changing colors. Let's modify selection.ts. Import { saveHistoryAtom } and invoke it before changing the color. This allows us to undo changing color too. Technically, we could improve it to undo selection and also add redo feature.
[1:45] In summary, we created a new history.ts file and defined a new shapeAtomsAtom. This replaces the original shapeAtomsAtom in SvgShapes.tsx and saves history before the change. The change in SvgShapes.tsx was minimal. We also enabled undo changing colors. You are free to extend the history feature more.