
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
react-state-history
Advanced tools
A React library for state management with undo and redo capabilities
A lightweight React library that provides state management with built-in undo and redo capabilities. Perfect for building applications that need history tracking, such as text editors, drawing applications, form builders, or any interactive UI where users might want to revert changes.
# Using pnpm (recommended)
pnpm add react-history-state
# Using npm
npm install react-history-state
# Using yarn
yarn add react-history-state
import { useHistoryState } from 'react-history-state';
function MyComponent() {
const {
state,
setState,
undo,
redo,
canUndo,
canRedo,
history,
reset
} = useHistoryState('initial value');
return (
<div>
<input
value={state}
onChange={(e) => setState(e.target.value)}
/>
<button onClick={undo} disabled={!canUndo}>
Undo
</button>
<button onClick={redo} disabled={!canRedo}>
Redo
</button>
<button onClick={reset}>
Reset
</button>
<p>History length: {history.length}</p>
</div>
);
}
useHistoryState<T>(initialState: T, options?: Options)The main hook that provides state management with history capabilities.
initialState: T - The initial state valueoptions?: Options - Configuration options (optional)interface Options {
maxHistory?: number; // Maximum history entries (default: 50)
debounceMs?: number; // Debounce state changes (default: 0)
enableRedo?: boolean; // Enable redo functionality (default: true)
onValueChange?: (value: T) => void; // Optional callback after each setState
}
interface StateHistory<T> {
state: T; // Current state value
setState: (value: T | ((prev: T) => T)) => void; // Update state
undo: () => void; // Undo last change
redo: () => void; // Redo next change
canUndo: boolean; // Whether undo is available
canRedo: boolean; // Whether redo is available
history: T[]; // Array of all history states
reset: () => void; // Reset to initial state
clear: () => void; // Clear all history
goToIndex: (index: number) => void; // Jump to specific history index
}
interface FormData {
name: string;
email: string;
age: number;
}
function FormComponent() {
const { state, setState, undo, redo, canUndo, canRedo } = useHistoryState<FormData>({
name: '',
email: '',
age: 0
});
const updateName = (name: string) => {
setState(prev => ({ ...prev, name }));
};
const updateEmail = (email: string) => {
setState(prev => ({ ...prev, email }));
};
return (
<form>
<input
value={state.name}
onChange={(e) => updateName(e.target.value)}
placeholder="Name"
/>
<input
value={state.email}
onChange={(e) => updateEmail(e.target.value)}
placeholder="Email"
/>
<div>
<button type="button" onClick={undo} disabled={!canUndo}>
Undo
</button>
<button type="button" onClick={redo} disabled={!canRedo}>
Redo
</button>
</div>
</form>
);
}
function TextEditor() {
const { state, setState, undo, redo, canUndo, canRedo } = useHistoryState('', {
maxHistory: 100, // Keep up to 100 history entries
debounceMs: 300, // Debounce rapid changes by 300ms
enableRedo: true, // Enable redo functionality
onValueChange: (val) => {
console.log('State changed to:', val);
},
});
return (
<div>
<textarea
value={state}
onChange={(e) => setState(e.target.value)}
rows={10}
cols={50}
/>
<div>
<button onClick={undo} disabled={!canUndo}>
Undo (Ctrl+Z)
</button>
<button onClick={redo} disabled={!canRedo}>
Redo (Ctrl+Y)
</button>
</div>
</div>
);
}
import { useEffect } from 'react';
import { useHistoryState } from 'react-history-state';
function ComponentWithKeyboardShortcuts() {
const { state, setState, undo, redo, canUndo, canRedo } = useHistoryState('');
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.ctrlKey || e.metaKey) {
if (e.key === 'z' && !e.shiftKey && canUndo) {
e.preventDefault();
undo();
} else if ((e.key === 'y' || (e.key === 'z' && e.shiftKey)) && canRedo) {
e.preventDefault();
redo();
}
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [undo, redo, canUndo, canRedo]);
return (
<textarea
value={state}
onChange={(e) => setState(e.target.value)}
/>
);
}
See CONTRIBUTING.md for development guidelines and setup instructions.
pnpm install
pnpm run build
pnpm test
pnpm test:watch
pnpm test:coverage
pnpm run lint
pnpm run lint:fix
Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.
This project is licensed under the MIT License - see the LICENSE file for details.
See CHANGELOG.md for a detailed history of changes.
FAQs
A React library for state management with undo and redo capabilities
We found that react-state-history demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.