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

bloody-flux

v1.3.2

Published

a server & client-side friendly implementation of flux

Downloads

13

Readme

bloody-flux

a server & client-side friendly implementation of flux

Build Status

bloody-flux is a server & client-friendly implementation of the flux architecture.

install

$ npm install bloody-flux --save

require

// ES6 module syntax
import { Dispatcher, Store, StoreReceiver, InitialData } from "bloody-flux"
// commonjs + ES6
var { Dispatcher, Store, StoreReceiver, InitialData } = require("bloody-flux")
// commonjs + ES5
var Flux = require("bloody-flux")
var Dispatcher = Flux.Dispatcher
// …

design choices

in order to be able to render components on the server, the singleton pattern for the stores & the dispatcher simply makes concurrency impossible. therefore in this flux implementation, stores & dispatchers are only used as singletons for the client-side.

using instances for the dispatcher also means you can't just require them to access them. to make their use possible, the dispatcher keeps its stores in a map, and components only need to get this dispatcher. in this implementation this is done through the react components' context.

here, actions creators are just simple functions without the dispatcher as dependency, they just return the action object, and you need to explicitely use dispatcher.dispatch(actionCreator(params)). this enables us to easily test them, and to avoid an extra dependency that makes it difficult to work with both the server and the client.

as mixins aren't available in ES6 classes, and the react team chose not to keep that feature before the language itself brings a good solution to compose classes, the way that is used to attach a store to a component is a higher- order component getting the stores data in its state, and passes it as props to the component needing it. to do that, a factory is used to "wrap" the user's components. a good consequence of this is that the user's component doesn't have to be stateful anymore, as its data comes in its props.

API

Dispatcher

const dispatcher = new Dispatcher()

creates a new dispatcher instance. Dispatcher is a subclass of facebook's flux dispatcher. you have its features in bloody-flux's dispatcher too.

dispatcher.registerStore(store)

registers a store, and makes it listen to dispatched actions.

the store must have a registerDispatcher method and a static displayName string property

dispatcher.getStore(displayName)

returns the registered store matching displayName

dispatcher.dispatch(action)

dispatches an action to the stores.

this action must be an object, and must contain a non-null type property in order to identify this action.

Dispatcher.getContextType()

shorthand to get a valid react PropType for a dispatcher instance.

import React, {Component} from "react"
import {Dispatcher} from "bloody-flux"

class MyComponent extends Component {
  static contextTypes = {
    ...Dispatcher.getContextType()
  }
}

Store

class MyStore extends Store { … }

to create a store, you first need to extend it.

static displayName

you must define a unique displayName string as a static property in order to identify your store.

the dispatcher will throw an error if you attempt to register two objects with the same static displayName

state

you can define an original state by setting a state object in your class spec.

// with ES7 property initializer
class MyStore extends Store {
  state = {
    property1 : value1
    // …
  }
}

// with ES6
class MyStore extends Store {
  constructor() {
    this.state = {
      property1 : value1
      // …
    }
    super()
  }
}

setState(nextState)

like react's setState, this method merges nextState with this.state in a new object, and emits a change event.

replaceState(nextState)

replaces the state by nextState, and emits a change event.

shouldEmitChange(prevState, nextState)

a method you can optionally define for a better performance if you send too much unnecessary change events. the change event is only sent if shouldEmitChange returns a truthy value.

by default, shouldEmitChange always returns true

class MyStore extends Store {
  // …
  shouldEmitChange(prevState, nextState) {
    if(prevState.id === nextState.id) {
      // don't send a change event if id didn't change
      return false
    }
    return true
  }
}

getActionHandlers()

a method where you return what method(s) should be executed for a given action. you must return an object with functions as values and action types as keys.

for a nicer syntax, you can take advantage of ES6's computed property names

methods are ran with the store as thisValue

import {ActionTypes} from "../constants"

class MyStore extends Store {
  updatePost(post) {
    this.setState({
      ...post.response
    })
  }
  getActionHandlers() {
    return {
      [ActionTypes.RECEIVE_POST] : this.updatePost,
      // you can even execute mutiple methods for a given action
      [ActionTypes.SOME_ACTION] : (action) => {
        this.someOtherMethod()
        this.updatePost(action)
      }
    }
  }
}

dispatcher

the store's dispatcher is set as the dispatcher once the store has been registered. this is useful to emit actions from the store API calls and to fetch other stores (for such features as waitFor)

dispatchToken

the store identifier in dispatcher.

store.addChangeListener(func)

registers func as a change listener. func will be executed each time a change event is emitted.

func will be passed the store's displayName as parameter

store.removeChangeListener(func)

unregisters func from the change listeners.

store.emitChange()

emits a change event.

StoreReceiver

StoreReceiver(ReactComponentClass)

factory to get store's data in ReactComponentClass props.

static stores

in the ReactComponentClass you wrap with StoreReceiver, you define which stores you want to receive data from in an object with displayNames as keys, and the props names you want them in as values.

import React, {Component} from "react"

class ReactComponentClass extends Component {
  // ReactComponentClass will receive PostStore's state in its "post" prop
  // and OtherStores's data in its "foo" prop
  statics stores = {
    PostStore : "post",
    OtherStore : "foo",
  }

  render() {
    return (
      <div>
        {this.props.post.title}
        {this.props.foo.someProp}
      </div>
    )
  }
}

InitialData

the InitialData react component is a component that is meant to be used with the renderToStaticMarkup react method on the server, to export data from the store in <script> tags with text/json type (so that the browser doesn't try to execute the JSON code).

the stores, when initialized, try to find a <script> tag with a data-storename attribute with their displayName as value.

prop stores

just pass the stores displayNames you want in an array passed to the stores prop.

InitialData must have the current dispatcher instance in its context.

import React, {Component} from "react"
import Dispatcher from "./Dispatcher"
import InitialData from "./InitialData"

const dispatcher = new Dispatcher()

// …

class App extends Component {
  static childContextTypes = {
    ...Dispatcher.getContextType()
  }

  getChildContext() {
    return {
      dispatcher
    }
  }

  render() {
    return (
      <this.props.component {...this.props} />
    )
  }
}

const stores = [
  "PostStore",
  "AuthorStore",
]
const initialData = React.renderToStaticMarkup(
  <App component={InitialData} stores={stores} />
)

adding the dispatcher in a react component's context

you need a parent component to add the dispatcher to your react components :

import React, {Component} from "react"
import Dispatcher from "./Dispatcher"

// create your app's dispatcher
// and register some stores
const dispatcher = new Dispatcher()

class App extends Component {
  static childContextTypes = {
    ...Dispatcher.getContextType()
  }
  getChildContext() {
    return {
      dispatcher
    }
  }
  render() {
    // return your component here
  }
}

React.render(<App />, mountNode)

license