← All tasksReact · Senior
Undo and redo
Write a useHistory(initial) hook - state with a change history. It returns { value, set, undo, redo, canUndo, canRedo }.
set(v) makes v the current value and remembers the previous one. undo() brings back the previous value, redo() the undone one. A new set after undo discards the redo branch. undo and redo do nothing without history. Several set calls in a row in one handler must all be recorded.
Ctrl+Enter runs the tests. Tab indents; to leave the editor with the keyboard, press Esc and then Tab. Your code is saved in this browser.
Tests (6)
const { result } = renderHook(() => useHistory('a')); expect(result.current.value).toBe('a'); expect(result.current.canUndo).toBe(false); expect(result.current.canRedo).toBe(false);
const { result } = renderHook(() => useHistory(0)); act(() => result.current.set(1)); act(() => result.current.set(2)); act(() => result.current.undo()); expect(result.current.value).toBe(1); act(() => result.current.undo()); expect(result.current.value).toBe(0); expect(result.current.canUndo).toBe(false);
const { result } = renderHook(() => useHistory(0)); act(() => result.current.set(1)); act(() => result.current.undo()); expect(result.current.canRedo).toBe(true); act(() => result.current.redo()); expect(result.current.value).toBe(1); expect(result.current.canRedo).toBe(false);
const { result } = renderHook(() => useHistory(0)); act(() => result.current.set(1)); act(() => result.current.set(2)); act(() => result.current.undo()); act(() => result.current.set(3)); expect(result.current.value).toBe(3); expect(result.current.canRedo).toBe(false); act(() => result.current.undo()); expect(result.current.value).toBe(1);
const { result } = renderHook(() => useHistory('x')); act(() => result.current.undo()); act(() => result.current.redo()); expect(result.current.value).toBe('x');
const { result } = renderHook(() => useHistory(0)); act(() => { result.current.set(1); result.current.set(2); }); act(() => result.current.undo()); expect(result.current.value).toBe(1);