撤销历史
编辑过程的一半是犯了小错误,并再次纠正它们。 因此,绘图程序中的一个非常重要的功能是撤消历史。
为了能够撤销更改,我们需要存储以前版本的图片。 由于这是一个不可变的值,这很容易。 但它确实需要应用状态中的额外字段。
我们将添加done数组来保留图片的以前版本。 维护这个属性需要更复杂的状态更新函数,它将图片添加到数组中。
但我们不希望存储每一个更改,而是一定时间量之后的更改。 为此,我们需要第二个属性doneAt,跟踪我们上次在历史中存储图片的时间。
function historyUpdateState(state, action) {if (action.undo == true) {if (state.done.length == 0) return state;return Object.assign({}, state, {picture: state.done[0],done: state.done.slice(1),doneAt: 0});} else if (action.picture &&state.doneAt < Date.now() - 1000) {return Object.assign({}, state, action, {done: [state.picture, ...state.done],doneAt: Date.now()});} else {return Object.assign({}, state, action);}}
当动作是撤消动作时,该函数将从历史中获取最近的图片,并生成当前图片。
或者,如果动作包含新图片,并且上次存储东西的时间超过了一秒(1000 毫秒),会更新done和doneAt属性来存储上一张图片。
撤消按钮组件不会做太多事情。 它在点击时分派撤消操作,并在没有任何可以撤销的东西时禁用自身。
class UndoButton {constructor(state, {dispatch}) {this.dom = elt("button", {onclick: () => dispatch({undo: true}),disabled: state.done.length == 0}, "⮪ Undo");}setState(state) {this.dom.disabled = state.done.length == 0;}}
