速记: 十分钟, 给我的 FlashCard 加上 Revert 功能
我认为: Revert 功能, 是一个 闪卡类 App 的刚需. 而且是必须足够简单明确, 操作应该足够简单便捷的刚需.
原因很简单: 谁都有手滑的时候. 纵然, 基于基于规则, 一个卡片手滑点错 OK 或者 NG, 对最终的记忆效果影响不会太大; 但是心里真的感觉很不舒服. 而且, 严格来说: 立即 Revert 这次操作, 能让闪卡更准确真实的反映用户的记忆状况.
这次的思路, 也很简单. 没有用 Redux 那一套复杂的 Redo/Undo 库. 我知道是可以的. 我记得我以前搞过.
说实话, 需求非常简单. 我也只需要 Undo 用户(其实现在只有我) 的最后一次 NG/OK 操作就行. 甚至都不用持久化, 直接存储到内存里就行. 因为这是一个强即时性的需求. 就像马路上开车, 遇到岔道, 该转向就要立即转向; 错过路口, 再操作方向盘, 可能完全没啥意义了.
我的基础思路:
- 内存里, 用单独一个变量, 记录最后一次 NG/OK 操作前, 该卡片的几个核心状态:
cardRevertEvent = {
cardId,
stage: card.stage,
reviewToday: card.reviewToday,
lastStudy: card.lastStudy,
}
- 然后, 界面上加个 Revert 按钮, 点击就执行 Revert 操作:
<button
type="button"
className="inline-flex items-center gap-x-2 rounded-md bg-red-400 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
onClick={() => {
if (window.confirm("确定 Revert 最后一次卡片操作吗?")) {
dispatch(reviewRevertAction())
}
}}
>
Revert卡片操作
</button>
- Revert 操作本身也非常简单, 就是把最后一次记录的 卡片关键状态, 给还原回去:
reviewRevertAction: {
reducer(state, action) {
if (!cardRevertEvent) {
return
}
const info = cardRevertEvent
const { cardId, stage, reviewToday, lastStudy } = cardRevertEvent
cardRevertEvent = null
const card = state.card[cardId]
card.stage = stage
card.reviewToday = reviewToday
card.lastStudy = lastStudy
localCacheCardState(state)
}
},
我要写的, 其实就是这些. 但是因为是基于 React + Redux. 可以自动实现UI的动态局部刷新, 所有体验是极好的.
啊! 再次感慨下! docker 下部署的 web 服务, 配合 –mount 本地目录. 这种修改后, 立即生效, 所写即所得的编码体验, 真的是太棒了! 换了其他方式, 我可能还在初始构建代码…