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 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-sman

v1.1.1

Published

Very easy to use and a pico state manager for react apps.

Readme

react-sman

npm version Licence Github issues Github stars

Very easy to use, a pico and immutable state manager for react apps. Great for simple apps.

Table of contents

The goal

Deliver a simple and easy way of managing the state for react applications. The API is very simple and it implements some of the concepts we find in a redux and redux-saga/thunk applications. Lastly, handle immutable state updates is also covered by the lib.

Install

npm i react-sman --save-prod

Set initial app state

For the example let's name this file app-state.js

import smanFactory from 'react-sman';

const state = {
  tvshows: [{
      name: 'Silicon Valley',
      seasons: 5,
      watched: false
    }, {
      name: 'Breaking Bad',
      seasons: 5,
      watched: false
    }, {
      name: 'Dark',
      seasons: 1,
      watched: false
    }
  ],
  selectedTvshow: null,
  loading: false
};

const sman = smanFactory({ state, debug: true });

export default sman;

Attach state to Component

We should only attach sman to container components, so this.state is back for them.

import React, { Component } from 'react';
import sman from './app-state';

class TvshowList extends Component {
  constructor(props) {
    super(props);

    // attach state sman to component - pass a list of key names (from sman) you need
    // you cannot rename state keys. Sounds bad right? not really!
    sman.attachState(this, ['tvshows', 'selectedTvshow', 'loading']);
  }

  _onClickTvshow(id, index) {
    // this.triggerAction() function will be available for all components using sman
    this.triggerAction('ON_SELECT', id, index);
  }

  render() {
    const { tvshows, selectedTvshow } = this.state;
    return (
      // ... my JSX
    );
  }
}

// ... prop-types and defaultProps ...

export default TvshowList;

Sman doesn't allow changing state keys when attaching state to a container component. First of all, let me remind you that sman it's designed mainly for small/medium apps, second point I want to make is that I understand why this can be considered an issue or a bad implementation of the library, in fact the implementation is completely intentional, the problem with renaming state keys per container is that it's very hard to reason about what data we're looking at, that said, just be sure give meaninful key names to your state keys in a way that they are unique and easy to identify.

Create actions

Actions work almost the same as in redux. You need to return an object with all fields we want to update. The main difference is that this object will update the state, so no reducer here. The reducer makes perfect sense and I'm not saying otherwise, but mainly what we usually do in a reducer is make sure that we don't mutate the state. react-sman does that already, it uses object-path-immutable as a helper to achieve that, so before updating the state the object is copied avoiding mutations. Just make sure you don't pass an object from the previous state to update state. Check the example bellow SET_WATCHED action is a good example of a deep copy that the manager will perform.

import sman from './app-state'; // wherever we created sman

sman.registerAction('LOADING', function(isLoading) {
  return {
    loading: isLoading
  };
});

sman.registerAction('SET_SELECTED', function(id) {
  return {
    selectedMovie: id
  };
});

sman.registerAction('SET_WATCHED', function(index) {
  // change only the field you need, don't produce
  // a deep copy the library alredy does it
  return {
    // path to leaf prop we want to update
    [`series.${index}.watched`]: true
  };
});

sman.registerAction callback can also be async.

Hijack an action execution

The hijack function allows you to catch an action when it's fired. Then you can perform async calls and trigger multiple actions inside the callback function. This is something similar as you can find some side effects manager libs such as redux-saga. Of course, this is just a very simple and minimal implementation of a function like take.


sman.hijack('ON_SELECT', async function(id, index) {
  await this.trigger('LOADING', true);
  // perform any async call
  try {
    const remoteData = await fetch();
    // ... do stuff with incoming data

    await this.trigger('SET_SELECTED', id);
    await this.trigger('SET_WATCHED', index);
  } catch (e) {
    console.error(e);
  } finally {
    // cleanup - if any error, even inside catch, this will run
    await this.trigger('LOADING', false);
  }
});

trigger function returns a Promise, so with that in mind when inside an sman.hijack function always use await when you need to trigger an action.

Contributions

Contributions are very welcome. There's a lot of room for improvements and new features so feel free to fork the repo and get into it. Also, let me know of any bugs you come across, any help on bug fixing is also a plus!