Fluxible
Pluggable container for isomorphic flux applications that provides interfaces that are common throughout the Flux architecture and restricts usage of these APIs to only the parts that need them to enforce the unidirectional flow.
Install
npm install --save fluxible
Usage
var Component = require('./components/Application.jsx');
var Fluxible = require('fluxible');
var app = new Fluxible({
component: Component
});
var context = app.createContext();
var loadPageAction = require('./actions/loadPage');
context.executeAction(loadPageAction, {}, function (err) {
if (err) throw err;
var element = context.createElement({});
var html = React.renderToString(element);
var appState = app.dehydrate(context);
...
});
For a more extensive example of usage both on the server and the client, see flux-examples.
Dehydration/Rehydration
Fluxible uses reserved methods throughout called rehydrate
and dehydrate
which are responsible for taking a snapshot of server-side state so that it can be sent to the browser and rehydrated back to the same state in the browser. This naming scheme also extends to dispatchr which takes care of dehydrating/rehydrating the store instances.
There are two kinds of state within fluxible:
- Application State: Settings and data that are registered on server start
- Context State: Settings and data that are created per context/request
Application level rehydrate method is allowed asynchronous operation in case it needs to load JavaScript or data on demand.
Context Types
Within a context, Fluxible creates interfaces providing access to only certain parts of the system. These are broken down as such:
- Action Context: interface accessible by action creator methods. Passed as first parameter to all action creators.
- Component Context: interface accessible by React components. Should be passed as prop to top level React component and then propagated to child components that require acess to it.
- Store Context: interface accessible by stores. Passed as first parameter to all stores. See dispatchr docs
Creating Plugins
Plugins allow you to extend the interface of each context type. Here, we'll give components access to the getFoo()
function:
var Fluxible = require('fluxible');
var app = new Fluxible();
app.plug({
name: 'TestPlugin',
plugContext: function (options) {
var foo = options.foo;
return {
plugComponentContext: function (componentContext) {
componentContext.getFoo = function () {
return foo;
};
},
dehydrate: function () {
return {
foo: foo
};
},
rehydrate: function (state) {
foo = state.foo;
}
};
},
dehydrate: function () { return {}; },
rehydrate: function (state) {}
});
var context = app.createContext({
foo: 'bar'
});
context.getComponentContext().getFoo();
Example plugins:
FluxibleComponent
The FluxibleComponent
is a wrapper component that will provide all of its children with access to the Fluxible component
context via React's context. This should be used to wrap your top level component:
var FluxibleComponent = require('fluxible').FluxibleComponent;
var Component = React.createClass({
contextTypes: {
getStore: React.PropTypes.func.isRequired
},
getInitialState: function () {
return this.getStore(FooStore).getState();
}
});
var html = React.renderToString(
<FluxibleComponent context={context.getComponentContext()}>
<Component />
</FluxibleComponent>
);
If you're using context.createElement(props)
, you will receive your component wrapped with a FluxibleComponent
.
FluxibleMixin
The mixin (accessible via require('fluxible').FluxibleMixin
) will add the contextTypes getStore
and executeAction
to your component and provides a a helper for listening to stores:
The mixin can also be used to statically list store dependencies and listen to them automatically in componentDidMount. This is done by adding a static property storeListeners
in your component.
You can do this with an array, which will default all store listeners to call the onChange
method:
var FluxibleMixin = require('fluxible').FluxibleMixin;
var MockStore = require('./stores/MockStore');
var Component = React.createClass({
mixins: [FluxibleMixin],
statics: {
storeListeners: [MockStore]
},
onChange: function () {
this.setState(this.getStore(MockStore).getState());
},
});
Or you can be more explicit with which function to call for each store by using a hash:
var FluxibleMixin = require('fluxible').FluxibleMixin;
var MockStore = require('./stores/MockStore');
var Component = React.createClass({
mixins: [FluxibleMixin],
statics: {
storeListeners: {
onMockStoreChange: [MockStore]
}
},
onMockStoreChange: function () {
this.setState(this.getStore(MockStore).getState());
},
});
This prevents boilerplate for listening to stores in componentDidMount
and unlistening in componentWillUnmount
.
Helper Utilities
Fluxible also exports dispatcher's store utilities so that you do not need to have an additional dependency on dispatchr. They are available by using require('fluxible/utils/BaseStore')
and require('fluxible/utils/createStore')
.
APIs
License
This software is free to use under the Yahoo Inc. BSD license.
See the LICENSE file for license text and copyright information.