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

nano-flux

v0.0.11

Published

Tiny, simple wrapper around Facebook's Flux library.

Downloads

32

Readme

NanoFlux

Just a tiny, simple wrapper around Facebook's flux dispatcher.

  • Hardly any code.
  • No classes, no use of this. Action creators are just functions. Stores are simple factory functions that return handlers.
  • No need to specify action creators that just pass through to store handlers. Having a store that specifies a handler implies an action creator that dispatches a matching action.
  • No singletons. The NanoFlux factory function creates your stores and action creators and wraps them up in a flux instance for you. Nice for testing or isomorphic apps or just plain clean code.

Examples

Implicit actions

If all your actions are just passing through to the store, you can forget all the boilerplate! This is great for testing a store.

import Flux from 'nano-flux';

// You specify a store with a factory function that takes a private store
// object as a parameter.
const createMessageStore = (store) => {

  // Setting the state here won't fire any events, so feel free to use
  // `setState` function for initialization.
  store.setState({
    messages: []
  });

  // Return handlers to listen for dispatched actions.
  return {

    addMessage(content) {
      // Using `setState` will automatically cause the store to emit a change
      // event.
      store.setState({
        messages: store.state.messages.concat(content)
      });
    }
  }
};

// Create a flux instance.
const flux = Flux.create({
  stores: {
    // The key becomes the namespace for the store.
    message: createMessageStore
  }
});

// Listen for change events on the store.
flux.stores.message.on('change', (state) => {
  console.log('Messages:', state.messages);
});

// Dispatch an action.
flux.actions.message.addMessage('Hello, world!');

Explicit actions

If your action needs to do a bit of work before dispatching, it's easy to add explict action creators. Note that if you define any action creators, no implicit ones will be created.

import Flux from 'nano-flux';

// Action creators are specified by simple objects with functions.
const messageActions = {

  // Each action creator function is passed a `dispatch` function bound to that
  // action.
  addMessage(dispatch, content) {
    const cid = (new Date()).getTime();
    // Dispatch signatures match the signature of the store's handlers.
    dispatch(cid, content);
  }

};

const createStore = (store) => {

  store.setState({
    messages: []
  });

  return {

    addMessage(cid, content) {
      store.setState({
        messages: store.state.messages.concat({
          cid: cid,
          content: content
        })
      });
    }
  }
};

const flux = Flux.create({
  actions: {
    // The key becomes the namespace for the actions.
    message: messageActions
  }
  stores: {
    message: createStore
  }
});

flux.stores.message.on('change', (state) => {
  console.log('Messages:', state.messages);
});

flux.actions.message.addMessage('Hello, world!');

waitFor

To wait for another store, use store.waitFor(storeKey). You can also read the state of another store via store.stores[storeKey].state.

Here's a silly example where the message store is dependent on an id store to create the ids.

const createIdStore = (store) => {

  store.setState({
    id: 0
  });

  return {

    // This wrapping key signifies that the action is coming from the "message"
    // actions namespace rather than the "id" namespace.
    message: {

      addMessage() {
        store.setState({
          id: store.state.id + 1
        });
      }
    }
  };
};

const createMessageStore = (store) => {

  store.setState({
    messages: []
  });

  return {

    addMessage(content) {
      // Here we wait for the "id" store to finish.
      store.waitFor('id');
      store.setState({
        messages: store.state.messages.concat({
          // Peeking at the (read-only) state of the "id" store.
          id: store.stores.id.state.id,
          content: content
        })
      });
    }
  };
};

const flux = Flux.create({
  stores: {
    message: createMessageStore,
    id: createIdStore
  }
});

Async

Implicit actions make it pretty easy to do async while explicit dispatch still makes it really clear. If your success and error action creators are just pass-through, no need to specify them.

import SomeDataService from '../some-data-service';

const messageActions = {

  addMessage(dispatch, content) {
    const cid = (new Date()).getTime();
    // Do the optimistic dispatch.
    dispatch(cid, content);
    SomeDataService.addMessage(content)
      .then((result) => {
        // Dispatch for success.
        dispatch.to.addMessageDone(cid, result.id);
      })
      .catch((error) => {
        // Dispatch for failure.
        dispatch.to.addMessageFail(cid, error);
      });
  }
};

const createMessageStore = (store) => {

  store.setState({
    messages: [],
    errors: []
  });

  return {

    addMessage(cid, content) {
      store.setState({
        messages: store.state.messages.concat({
          cid: cid,
          content: content
        })
      });
    },

    addMessageDone(cid, id) {
      const index = _.findIndex(store.state.messages, (message) => {
        return message.cid === cid;
      });

      const newState = update(store.state, {
        messages: {
          [index]: {
            id: {$set: id}
          }
        }
      });

      store.setState(newState);
    },

    addMessageFail(cid, error) {
      const newState = update(store.state, {
        errors: {
          $push: [error]
        }
      });

      store.setState(newState);
    }
  };
};

const flux = Flux.create({
  actions: {
    message: messageActions
  },
  stores: {
    message: createMessageStore
  }
});

flux.actions.message.addMessage('Hey, that was pretty easy!');

Action creators from factories

The examples above show the action creators as just functions in an object. You can also use a factory to create your action creators. This keeps the api more consistent. Just remember: if you start holding on to state inside the closure, you're probably cheating!

import SomeDataService from '../some-data-service';

const createMessageActions = (actions) => {

  addMessage(dispatch, content) {
    const cid = (new Date()).getTime();
    // Do the optimistic dispatch.
    dispatch(cid, content);
    SomeDataService.addMessage(content)
      .then((result) => {
        // Dispatch for success.
        actions.addMessageDone(cid, result.id);
      })
      .catch((error) => {
        // Dispatch for failure.
        actions.addMessageFail(cid, error);
      });
  }
};

const createMessageStore = (store) => {
  ...
};

const flux = Flux.create({
  actions: {
    message: createMessageActions
  },
  stores: {
    message: createMessageStore
  }
});

One benefit of this is it makes it easy to bind your actions to other dependencies, like a data service.

const createMessageActions = (DataService, actions) => {
  ...
};

const createMessageStore = (store) => {
  ...
};

const flux = Flux.create({
  actions: {
    message: createMessageActions.bind(null, SomeDataService)
  },
  stores: {
    message: createMessageStore
  }
});

Add-ons

connectToStores

Higher-order component to listen to stores and pass state to a wrapped component.

import Flux from 'nano-flux/addons';
import Message from './message';

const Messages = React.createClass({
  render() {
    return (
      <ul>
        {this.props.messages.map((message) => {
          return <Message message={message}/>;
        })}
      </ul>
    )
  }
});

const ConnectedMessages = Flux.addons.connectToStores(Messages, ['message'], (stores, props) => {
  return {
    messages: stores.message.state.messages
  };
});

React.render(<ConnectedMessages flux={flux}/>);

injectActions

Higher-order component to pass actions to a wrapped component. Use with connectToStores to remove the need to pass around the flux object at all.

import Flux from 'nano-flux/addons';
import Message from './message';

const Messages = React.createClass({
  render() {
    return (
      <div>
        <ul>
          {this.props.messages.map((message) => {
            return <Message message={message}/>;
          })}
        </ul>
        <button onClick={this.props.addMessage}>Add Message</button>
      </div>
    )
  }
});

const ConnectedMessages = Flux.addons.connectToStores(Messages, ['message'], (stores, props) => {
  return {
    messages: stores.message.state.messages
  };
});

const ActionMessages = Flux.addons.injectActions(ConnectedMessages, ['message'], (actions) => {
  return actions.message;
});

React.render(<ActionMessages flux={flux}/>);