I am using solid-record to build a mind mapping application. The data in the application is a tree of nodes, and I want the ability to reparent a node, with undo/redo. The issue I am facing is that even though the undoing operation works fine, the redoing one does not.
I have recreated my issue in a simple application:
import { Component, For } from 'solid-js'
import { createStore } from 'solid-js/store'
import { createHistory } from 'solid-record'
type Node = {
id: number,
children: Array<number>
parentid: number
}
const initialValue = [
{ id: 0, children: [1, 2, 3], parentid: -1 },
{ id: 1, children: [], parentid: 0 },
{ id: 2, children: [], parentid: 0 },
{ id: 3, children: [], parentid: 0 },
]
const [state, setState] = createStore(initialValue)
const undoHistory = createHistory()
const changeState = () => {
undoHistory.batch()
const nodeid = 3
const oldparentid = 0
const newparentid = 2
let node = state[nodeid]
let oldparent = state[oldparentid]
let newparent = state[newparentid]
// first remove node form parent's children
undoHistory.add(setState, n => n.id === node.parentid, 'children', oldparent.children.filter(n => n !== node.id))
// then add to new parent's children
undoHistory.add(setState, n => n.id === newparent.id, 'children', [...newparent.children, node.id])
// lastly, point to new parent
undoHistory.add(setState, n => n.id === node.id, 'parentid', newparent.id)
undoHistory.unbatch()
}
const App: Component = () => {
return (
<>
<For each={state}>{(node: Node) => <div>{`id: ${node.id}, parentid: ${node.parentid}, children: ${node.children}`}</div>}</For>
<button onClick={changeState}>Change Parent of 3</button>
<button onClick={() => undoHistory.undo()} disabled={!undoHistory.isUndoable()}>Undo</button>
<button onClick={() => undoHistory.redo()} disabled={!undoHistory.isRedoable()}>Redo</button>
</>
);
};
export default App;
When clicking the 'Change parent of 3' button, the changeState function:
- removes node 3 from its parent (node 0) list of children
- adds node 3 to its new parent (node 2) list of children
- resets the parent of node 3 to 2
Redo properly restores the state to its initial value with 1,2,3 listed as children of 0.
But Redo sets the list of node 0's children to 3 where it should set it to 1,2! VERY strangely, this does not happen if I don't set the parentis property of node 3, which has no direct relation to the children property of node 0...
I suspect this is a reference vs value kind of problem, or it may be a bug in solid-record ... Any help?