<div id="app"></div>
/*
* https://frontendeval.com/questions/undoable-counter
*
* Create a simple counter with undo/redo functionality
*/
import React, { useState } from "https://esm.sh/react@17";
import ReactDOM from "https://esm.sh/react-dom@17";
function UndoCounter() {
const [count, setCount] = useState(0);
const [history, setHistory] = useState([]);
const [undo, setUndo] = useState([]);
function redoLast() {
if (undo.length == 0) {
return;
}
var lastUndo = undo.pop();
var newUndo = undo.slice();
var newHistory = history.slice();
newHistory.push(lastUndo);
var newCount = count + lastUndo.val;
setCount(newCount);
setUndo(newUndo);
setHistory(newHistory);
}
function undoLast() {
if (history.length == 0 || undo.length >= 50) {
return;
}
var lastHistory = history.pop();
var newUndo = undo.slice();
var newHistory = history.slice();
newUndo.push(lastHistory);
var newCount = count - lastHistory.val;
setCount(newCount);
setUndo(newUndo);
setHistory(newHistory);
}
function calculateCount(val) {
var newHistory = history.slice();
var newVal = count + val;
newHistory.push({'val': val, 'before': count, 'after': newVal, 'id' : newHistory.length});
setCount(newVal);
setHistory(newHistory);
}
return (
<>
<div>
<button onClick={undoLast}>Undo</button>
<button disabled={undo.length == 0} onClick={redoLast}>Redo</button>
</div>
<button onClick={() => calculateCount(-100)}>-100</button>
<button onClick={() => calculateCount(-10)}>-10</button>
<button onClick={() => calculateCount(-1)}>-1</button>
<span> {count} </span>
<button onClick={() => calculateCount(1)}>+1</button>
<button onClick={() => calculateCount(10)}>+10</button>
<button onClick={() => calculateCount(100)}>+100</button>
<ul>
{history.map((row) => {
return (
<li key={row.id}>{row.val} ({row.before} -> {row.after})</li>
);
})}
</ul>
</>
);
}
const App = () => {
return (
<UndoCounter />
);
}
ReactDOM.render(<App />, document.getElementById('app'));
View Compiled
This Pen doesn't use any external CSS resources.