npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

redux-state-history

v0.1.4

Published

Redux store enhancers for tracking and visualizing state changes

Downloads

7

Readme

Redux State History

Build Status

Redux store enhancers / component for tracking and visualizing state changes & debugging remote sessions.

Inspired by the redux devtools and redux slider monitor, this package provides state recording/playback (i.e. "time travel") abilities for redux applications.

Features:

  • Record state history efficiently locally / on production: Only state diffs are stored for each state change (performance untested for large state/long running applications).
  • Decoupled recording/debugging code: On production include only recording store enhancer for small footprint. Locally, use additional debug slider component to navigate/interact with the history.
  • Import/Export histories: Play them back locally, including realtime speed.
  • Time-travel is "pure": That is, state history changes without refiring the actual actions that produced said change (so still works for impure/async actions).

State history tracker:

A store enhancer provides the history tracking on each state change, recording the state change, the timestamp of the change, and the action type that produced said change. This is independent of the debug slider and can be used in production, requiring minimum dependencies (~16kb gzipped).

  • The actual state history is stored in the redux store under .stateHistory key.

Installation:

The state history tracker is installed as a store enhancer, in the same way other redux store enhancers like applyMiddleware, or the redux devtools are added

import { createStore, applyMiddleware, compose } from 'redux';
import rootReducer from '../reducers/index';
import DevTools from '../containers/DevTools.tsx';
import thunk from 'redux-thunk';
let createHistory = require('history/lib/createHashHistory');
let createLogger = require('redux-logger');
let { syncReduxAndRouter } = require('redux-simple-router');
import trackHistory from './Middleware';

const finalCreateStore = compose(
  debugStateHistory,
  applyMiddleware(thunk),
  applyMiddleware(createLogger()),
  trackHistory()                              // STATE HISTORY STORE ENHANCER
  DevTools.instrument()
)(createStore);

export const history = createHistory();

export default function configureStore() {
  const store = finalCreateStore(rootReducer);
  syncReduxAndRouter(history, store);

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextRootReducer = require('../reducers');
      store.replaceReducer(nextRootReducer);
    });
  }

  return store;
}

Dev slider tool

This component provides state history interactivity, plus allows importing and exporting state sessions.

Installation:

Store enhancer:

The debug component needs a store enhancer to work (it uses it to replace the current state by whichever state is selected from the history, so needs root-level access). To install it, you follow the same logic as the state history tracker above

// ... some code
const finalCreateStore = compose(
  debugStateHistory,                          // DEBUG SLIDER STORE ENHANCER
  applyMiddleware(thunk),
  applyMiddleware(createLogger()),
  trackHistory()                              // STATE HISTORY STORE ENHANCER
  DevTools.instrument()
)(createStore);
// ... more code

Component

You can include the StateHistoryDevTool component anywhere in your application as long as you provide the store.stateHistory properties. For example, in your root component, you can do

import * as React from 'react';
import { Provider } from 'react-redux';
import StateHistoryDevTool from './Component.tsx';
import Routes from '../routes.tsx';
import { Router } from 'react-router';
import { history } from '../store/configureStore.dev';

type IRootProps = {
  store: any
}

export default class Root extends React.Component<IRootProps, any> {
  public render() {
    const { store } = this.props;
    return (
        <Provider store={store}>
          <div>
            <Router history={ history }>
              { Routes }
            </Router>
            <StateHistoryDevTool { ...store.stateHistory } />
          </div>
        </Provider>
    );
  }
};

Note: On Combine Reducers:

If you use redux's combineReducers to set up your root reducer, you need to add a dummy "identity" reducer under the stateHistory key, otherwise the combinedReducers function will complain about that key not being predefined and drop it from the state.

const rootReducer = combineReducers({
  key: someReducer,
  key2: anotherReducer,
  ...
  stateHistory: (state = {}, action) => state, // dummy reducer to prevent combineReducers checks from throwing error
});