History Session Manager
The `history` library provides a robust and environment-agnostic API for managing session history in JavaScript applications, abstracting away the complexities of different platforms (browser, hash, memory). It allows developers to manage the history stack, navigate programmatically, and persist state across sessions. The current stable version is 5.3.0. Releases are generally aligned with React Router versions, as it's a core dependency for React Router v6. Key differentiators include its pluggable architecture for different history implementations (browser, hash, memory) and its strong TypeScript support, making it suitable for both web applications and server-side rendering or testing environments. It offers a consistent API regardless of the underlying history mechanism, simplifying routing logic in SPAs.
Common errors
-
TypeError: (0 , history__WEBPACK_IMPORTED_MODULE_0__.createBrowserHistory) is not a function
cause This error typically occurs when a CommonJS module attempts to consume `history` as an ESM-only default export, or when there's a mismatch in how named exports are handled in a mixed CJS/ESM environment (e.g., Webpack's interpretation).fixEnsure your project is configured for native ESM if you're using `import` statements. If using `require()`, adapt to `const { createBrowserHistory } = require('history');` for named exports, or configure your bundler to handle ESM interop correctly, especially in Node.js environments with `type: 'module'`. -
Property 'state' does not exist on type 'Location'. Did you mean 'State'?
cause This TypeScript error indicates an attempt to access `location.state` when the `Location` type no longer includes a strongly typed `state` property, specifically after the changes in v5.0.2 and v5.1.0.fixFor `history` v5, `location.state` is typed as `any` or `unknown`. Access `location.state` directly, and apply runtime type narrowing or explicit type assertions if you expect a specific type, e.g., `const myState = history.location.state as { from: string };` or `if (typeof history.location.state === 'object' && history.location.state !== null) { /* safe access */ }`. -
TS2307: Cannot find module 'history' or its corresponding type declarations.
cause TypeScript cannot locate the type definitions for the `history` package. This can happen if the package is not installed, if `@types/history` is missing (for `history` v4), or if `@types/history` is conflicting with `history` v5's built-in types.fixFor `history` v5 and newer, types are bundled. Ensure `history` is correctly installed via `npm install history`. If on `history` v4, install `@types/history` (`npm install --save-dev @types/history`). If on `history` v5 and still seeing this, ensure you have removed `@types/history`.
Warnings
- breaking Version 5.3.0 introduced native ESM consumption for all exports. While this aligns with modern JavaScript module standards, it might require adjustments for older build tools, Node.js versions, or environments that previously relied on specific CommonJS export behaviors or non-standard ESM patterns. Ensure your tooling is configured for native ESM.
- breaking Type declarations for `State`, `PartialPath`, and `PartialLocation` were deprecated in v5.2.0. The `State` type is now `unknown`, requiring explicit consumer type narrowing at runtime. `PartialPath` should be replaced with `Partial<Path>`, and `PartialLocation` with `Partial<Location>`.
- breaking The `Location` type generic for state was removed in v5.0.2, causing potential type conflicts. Although `location.state` was subsequently typed as `any` and the `State` type export restored in v5.1.0 for compatibility, direct usage of `Location<T>` for strongly typing `state` is no longer supported as it was in v4.
- gotcha Since v5.0.0-beta.5 (and stable v5.0.0), the `history` library includes its own TypeScript type definitions. Installing `@types/history` alongside `history@5` will lead to duplicate type declarations and compilation errors.
Install
-
npm install history -
yarn add history -
pnpm add history
Imports
- createBrowserHistory
const createBrowserHistory = require('history').createBrowserHistory;import { createBrowserHistory } from 'history'; - History
import type { History } from 'history'; - createPath
import createPath from 'history/createPath';
import { createPath } from 'history';
Quickstart
import { createBrowserHistory, createHashHistory, createMemoryHistory } from 'history';
// Create a browser history instance for web applications
const browserHistory = createBrowserHistory();
console.log('Initial browser history location:', browserHistory.location.pathname);
// Listen for changes in the history stack
browserHistory.listen(({ location, action }) => {
console.log(`Browser history changed: ${action} to ${location.pathname}${location.search}${location.hash}`);
});
// Navigate to a new path with state
browserHistory.push('/about', { from: 'home' });
// Replace the current entry in the history stack
browserHistory.replace('/contact');
// Create a hash history instance (for environments where server-side routing is not possible)
const hashHistory = createHashHistory();
console.log('Initial hash history location:', hashHistory.location.pathname);
hashHistory.push('/#/settings');
// Create a memory history instance (useful for testing or server-side rendering)
const memoryHistory = createMemoryHistory({ initialEntries: ['/', '/dashboard'] });
memoryHistory.go(-1);
console.log('Memory history location:', memoryHistory.location.pathname);
// Example of blocking navigation using `history.block`
const unblock = browserHistory.block((tx) => {
console.warn(`Blocking navigation attempt to ${tx.location.pathname}.`);
// To proceed with the navigation, uncomment tx.retry();
// tx.retry();
// Returning false or nothing cancels the navigation.
return false;
});
// Attempt to navigate, which will be blocked by the above listener
browserHistory.push('/secret-page');
// Clean up the blocker after a timeout for demonstration
setTimeout(() => {
unblock(); // Remove the navigation blocker
console.log('Navigation blocker removed. Subsequent navigations will proceed.');
browserHistory.push('/allowed-page'); // This navigation will now succeed
}, 2000);