Comparing version 0.3.3 to 0.4.0
@@ -1,1 +0,7 @@ | ||
module.exports = require('dispatchr/utils/BaseStore'); | ||
/** | ||
* Copyright 2015, Yahoo Inc. | ||
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. | ||
*/ | ||
'use strict'; | ||
module.exports = require('dispatchr/addons/BaseStore'); |
@@ -1,1 +0,7 @@ | ||
module.exports = require('dispatchr/utils/createStore'); | ||
/** | ||
* Copyright 2015, Yahoo Inc. | ||
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. | ||
*/ | ||
'use strict'; | ||
module.exports = require('dispatchr/addons/createStore'); |
@@ -0,4 +1,14 @@ | ||
/** | ||
* Copyright 2015, Yahoo Inc. | ||
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. | ||
*/ | ||
'use strict'; | ||
module.exports = { | ||
BaseStore: require('./BaseStore'), | ||
createStore: require('./createStore') | ||
connectToStores: require('./connectToStores'), | ||
createStore: require('./createStore'), | ||
FluxibleComponent: require('./FluxibleComponent'), | ||
FluxibleMixin: require('./FluxibleMixin'), | ||
provideContext: require('./provideContext') | ||
}; |
20
index.js
@@ -5,13 +5,11 @@ /** | ||
*/ | ||
module.exports = module.exports.Fluxible = require('./lib/Fluxible'); | ||
module.exports.FluxibleMixin = require('./lib/FluxibleMixin'); | ||
module.exports.FluxibleComponent = require('./lib/FluxibleComponent'); | ||
var Fluxible = require('./lib/Fluxible'); | ||
Fluxible.Fluxible = require('./lib/Fluxible'); | ||
Fluxible.contextTypes = require('./lib/contextTypes'); | ||
// Deprecated | ||
var objectAssign = require('object-assign'); | ||
module.exports.Mixin = objectAssign({}, require('./lib/FluxibleMixin'), { | ||
componentWillMount: function () { | ||
console.warn("require('fluxible').Mixin is deprecated. Please use " + | ||
"require('fluxible').FluxibleMixin."); | ||
} | ||
}); | ||
// DEPRECATIONS | ||
// @TODO(next minor): remove all deprecations | ||
Fluxible.FluxibleComponent = require('./lib/FluxibleComponent'); | ||
Fluxible.FluxibleMixin = require('./lib/FluxibleMixin'); | ||
module.exports = Fluxible; |
@@ -8,5 +8,6 @@ /** | ||
var debug = require('debug')('Fluxible'); | ||
var async = require('async'); | ||
var PromiseLib = global.Promise || require('es6-promise').Promise; | ||
var isPromise = require('is-promise'); | ||
var FluxibleContext = require('./FluxibleContext'); | ||
var dispatcherClassFactory = require('dispatchr'); | ||
var dispatchr = require('dispatchr'); | ||
var React = require('react'); | ||
@@ -19,3 +20,2 @@ | ||
* @param {Object} [options] | ||
* @param {Object} [options.appComponent] (DEPRECATED) | ||
* @param {Object} [options.component] The root application component | ||
@@ -38,15 +38,20 @@ * @param {String} [options.pathPrefix] The path used for application calls | ||
// Options | ||
this._component = options.component || options.appComponent; | ||
this._component = options.component; | ||
this._componentActionHandler = options.componentActionHandler || this._defaultComponentActionHandler; | ||
this._plugins = []; | ||
if (options.appComponent) { | ||
console.warn("*** `appComponent` is deprecated. " + | ||
"Please update your code to use `component` ***\n"); | ||
if ('production' !== process.env.NODE_ENV) { | ||
if (!this._component.hasOwnProperty('prototype')) { | ||
console.warn('It is no longer necessary to wrap your component with ' + | ||
'`React.createFactory` when instantiating Fluxible. Support for factories' + | ||
'will be removed in the next version of Fluxible.'); | ||
} | ||
} | ||
// Initialize dependencies | ||
this._dispatcherClass = dispatcherClassFactory(); | ||
this._dispatcher = dispatchr.createDispatcher(options); | ||
} | ||
Fluxible.Promise = PromiseLib; | ||
/** | ||
@@ -79,3 +84,2 @@ * Creates an isolated context for a request/session | ||
* @method defaultComponentActionHandler | ||
* @param {Error} [err] | ||
* @private | ||
@@ -95,7 +99,7 @@ */ | ||
* @method createDispatcherInstance | ||
* @param {Object} context The context object to be provided to each store instance | ||
* @param {Object} contextOptions The context options to be provided to each store instance | ||
* @returns {Dispatcher} | ||
*/ | ||
Fluxible.prototype.createDispatcherInstance = function createDispatcherInstance(context) { | ||
return new (this._dispatcherClass)(context); | ||
Fluxible.prototype.createDispatcherInstance = function createDispatcherInstance(contextOptions) { | ||
return this._dispatcher.createContext(contextOptions); | ||
}; | ||
@@ -148,12 +152,2 @@ | ||
/** | ||
* (DEPRECATED) | ||
* Getter for the top level react component for the application | ||
* @method getComponent | ||
* @returns {Object} | ||
*/ | ||
Fluxible.prototype.getAppComponent = function getAppComponent() { | ||
return this._component; | ||
}; | ||
/** | ||
* Registers a store to the dispatcher so it can listen for actions | ||
@@ -164,3 +158,3 @@ * @method registerStore | ||
debug(arguments[0].storeName + ' store registered'); | ||
this._dispatcherClass.registerStore.apply(this._dispatcherClass, arguments); | ||
this._dispatcher.registerStore.apply(this._dispatcher, arguments); | ||
}; | ||
@@ -204,31 +198,42 @@ | ||
var self = this; | ||
var Promise = Fluxible.Promise; | ||
obj.plugins = obj.plugins || {}; | ||
var pluginTasks = this._plugins.filter(function (plugin) { | ||
var pluginTasks = self._plugins.filter(function (plugin) { | ||
return 'function' === typeof plugin.rehydrate; | ||
}).map(function (plugin) { | ||
return function (asyncCallback) { | ||
if (2 === plugin.rehydrate.length) { // Async plugin | ||
plugin.rehydrate(obj.plugins[plugin.name], asyncCallback); | ||
} else { // Sync plugin | ||
try { | ||
plugin.rehydrate(obj.plugins[plugin.name]); | ||
} catch (e) { | ||
asyncCallback(e); | ||
return; | ||
return new Promise(function (resolve, reject) { | ||
var result = plugin.rehydrate(obj.plugins[plugin.name], function (err) { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(); | ||
} | ||
asyncCallback(); | ||
}); | ||
if (isPromise(result)) { | ||
result.then(resolve, reject); | ||
} else if (plugin.rehydrate.length < 2) { | ||
resolve(); | ||
} | ||
}; | ||
}); | ||
}); | ||
async.parallel(pluginTasks, function rehydratePluginTasks(err) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
var context = self.createContext(); | ||
context.rehydrate(obj.context, callback); | ||
var context = self.createContext(); | ||
var rehydratePromise = Promise.all(pluginTasks).then(function rehydratePluginTasks() { | ||
return context.rehydrate(context); | ||
}); | ||
if (callback) { | ||
rehydratePromise | ||
.then(function(context) { | ||
// Ensures that errors in callback are not swallowed by promise | ||
setImmediate(callback, null, context); | ||
}, function (err) { | ||
// Ensures that errors in callback are not swallowed by promise | ||
setImmediate(callback, err); | ||
}); | ||
} | ||
return rehydratePromise; | ||
}; | ||
module.exports = Fluxible; |
@@ -1,30 +0,20 @@ | ||
var React = require('react/addons'); | ||
/** | ||
* Copyright 2015, Yahoo Inc. | ||
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. | ||
*/ | ||
'use strict'; | ||
var FluxibleComponent = React.createClass({ | ||
displayName: 'FluxibleComponent', | ||
propTypes: { | ||
context: React.PropTypes.object.isRequired | ||
}, | ||
//@TODO(next minor) remove this file | ||
var FluxibleComponent = require('../addons/FluxibleComponent'); | ||
childContextTypes: { | ||
getStore: React.PropTypes.func, | ||
executeAction: React.PropTypes.func | ||
}, | ||
if ('production' !== process.env.NODE_ENV) { | ||
var deprecateComponent = require('../utils/deprecateComponent'); | ||
FluxibleComponent = deprecateComponent( | ||
FluxibleComponent, | ||
"require('fluxible').FluxibleComponent has been moved out of the " + | ||
"default exports for Fluxible. Please use " + | ||
"require('fluxible/addons/FluxibleComponent') instead." | ||
); | ||
} | ||
/** | ||
* Provides the current context as a child context | ||
* @method getChildContext | ||
*/ | ||
getChildContext: function () { | ||
return { | ||
getStore: this.props.context.getStore, | ||
executeAction: this.props.context.executeAction | ||
}; | ||
}, | ||
render: function () { | ||
return React.addons.cloneWithProps(this.props.children, this.props); | ||
} | ||
}); | ||
module.exports = FluxibleComponent; |
@@ -8,5 +8,7 @@ /** | ||
var debug = require('debug')('Fluxible:Context'); | ||
var objectAssign = require('object-assign'); | ||
var isPromise = require('is-promise'); | ||
var PromiseLib = global.Promise || require('es6-promise').Promise; | ||
var React = require('react'); | ||
var FluxibleComponent = React.createFactory(require('./FluxibleComponent')); | ||
var async = require('async'); | ||
var FluxibleComponent = require('../addons/FluxibleComponent'); | ||
require('setimmediate'); | ||
@@ -39,2 +41,5 @@ | ||
// Provied a way to override Promise only for FluxContext | ||
FluxContext.Promise = PromiseLib; | ||
/** | ||
@@ -51,5 +56,10 @@ * Creates an instance of the app level component with given props and a proper component | ||
} | ||
if ('ContextProvider' === Component.displayName) { | ||
return React.createElement(Component, objectAssign({}, { | ||
context: this.getComponentContext() | ||
}, props)) | ||
} | ||
var componentInstance; | ||
if (!Component.hasOwnProperty('prototype')) { | ||
// TODO: add warning to deprecate factories | ||
// TODO: remove factory support | ||
componentInstance = Component(props); | ||
@@ -59,3 +69,3 @@ } else { | ||
} | ||
return FluxibleComponent({ | ||
return React.createElement(FluxibleComponent, { | ||
context: this.getComponentContext() | ||
@@ -90,6 +100,11 @@ }, componentInstance); | ||
* Executes an action passing an action interface to as the first parameter | ||
* If a promise is returned by the action, it will wait for its resolution or rejection | ||
* If the action has less than three parameters, the returned promise | ||
* will be resolved with the return value | ||
* If the action throws an error, the promise will be rejected with the thrown value | ||
* @param {Function} action An action creator function that receives actionContext, payload, | ||
* and done as parameters | ||
* @param {Object} payload The action payload | ||
* @param {Function} done Method to be called once action execution has completed | ||
* @param {Function} [done] Method to be called once action execution has completed | ||
* @return {Promise} executeActionPromise Resolved with action result or rejected with action error | ||
*/ | ||
@@ -100,6 +115,31 @@ FluxContext.prototype.executeAction = function executeAction(action, payload, done) { | ||
var displayName = action.displayName || action.name; | ||
setImmediate(function executeActionImmediate() { | ||
var Promise = FluxContext.Promise; | ||
var executeActionPromise = new Promise(function executeActionPromise(resolve, reject) { | ||
debug('Executing action ' + displayName + ' with payload', payload); | ||
action(self.getActionContext(), payload, done); | ||
var result = action(self.getActionContext(), payload, function(err, result) { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(result); | ||
} | ||
}); | ||
if (isPromise(result)) { | ||
result.then(resolve, reject); | ||
} else if (action.length < 3) { | ||
resolve(result); | ||
} | ||
}); | ||
if (done) { | ||
executeActionPromise | ||
.then(function(result) { | ||
// Ensures that errors in callback are not swallowed by promise | ||
setImmediate(done, null, result); | ||
}, function (err) { | ||
// Ensures that errors in callback are not swallowed by promise | ||
setImmediate(done, err); | ||
}); | ||
} | ||
return executeActionPromise; | ||
}; | ||
@@ -167,3 +207,3 @@ | ||
executeAction: function componentExecuteAction(action, payload) { | ||
self.executeAction(action, payload, function actionHandlerWrapper(err) { | ||
self.executeAction(action, payload).catch(function actionHandlerWrapper(err) { | ||
var noop = function () {}; | ||
@@ -238,31 +278,29 @@ self.executeAction(self._app._componentActionHandler, { err: err }, noop); | ||
*/ | ||
FluxContext.prototype.rehydrate = function rehydrate(obj, callback) { | ||
FluxContext.prototype.rehydrate = function rehydrate(obj) { | ||
var self = this; | ||
var Promise = FluxContext.Promise; | ||
obj.plugins = obj.plugins || {}; | ||
var pluginTasks = this._plugins.filter(function (plugin) { | ||
var pluginTasks = self._plugins.filter(function (plugin) { | ||
return 'function' === typeof plugin.rehydrate; | ||
}).map(function (plugin) { | ||
return function (asyncCallback) { | ||
if (2 === plugin.rehydrate.length) { // Async plugin | ||
plugin.rehydrate(obj.plugins[plugin.name], asyncCallback); | ||
} else { // Sync plugin | ||
try { | ||
plugin.rehydrate(obj.plugins[plugin.name]); | ||
} catch (e) { | ||
asyncCallback(e); | ||
return; | ||
return new Promise(function (resolve, reject) { | ||
var result = plugin.rehydrate(obj.plugins[plugin.name], function (err) { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(); | ||
} | ||
asyncCallback(); | ||
}); | ||
if (isPromise(result)) { | ||
result.then(resolve, reject); | ||
} else if (plugin.rehydrate.length < 2) { | ||
resolve(); | ||
} | ||
}; | ||
}); | ||
}); | ||
async.parallel(pluginTasks, function rehydratePluginTasks(err) { | ||
if (err) { | ||
callback(err); | ||
return; | ||
} | ||
return Promise.all(pluginTasks).then(function rehydratePluginTasks() { | ||
self._dispatcher = self._app.createDispatcherInstance(self.getStoreContext()); | ||
self._dispatcher.rehydrate(obj.dispatcher || {}); | ||
callback(null, self); | ||
return self; | ||
}); | ||
@@ -269,0 +307,0 @@ }; |
/** | ||
* Copyright 2014, Yahoo! Inc. | ||
* Copyright 2015, Yahoo Inc. | ||
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. | ||
@@ -7,217 +7,18 @@ */ | ||
/** | ||
* React mixin for staticly declaring and add/remove-ing listeners for Store events. | ||
* @class FluxibleMixin | ||
* @example | ||
* // Register listener default handler function name | ||
* var Component = React.createClass({ | ||
* mixins: [FluxibleMixin], | ||
* statics: { | ||
* storeListeners: [FooStore] | ||
* }, | ||
* onChange: function () { | ||
* this.setState(this.context.getStore(FooStore).getState()); | ||
* }, | ||
* ... | ||
* }); | ||
* @example | ||
* // Register listener with custom named handler | ||
* var Component = React.createClass({ | ||
* mixins: [FluxibleMixin], | ||
* statics: { | ||
* storeListeners: { | ||
* 'onChange2': [FooStore] | ||
* } | ||
* }, | ||
* onChange2: function () { | ||
* this.setState(this.context.getStore(FooStore).getState()); | ||
* }, | ||
* ... | ||
* }); | ||
*/ | ||
var DEFAULT_CHANGE_HANDLER = 'onChange'; | ||
var React = require('react'); | ||
//@TODO(next minor) remove this file | ||
var FluxibleMixin = require('../addons/FluxibleMixin'); | ||
var FluxibleMixin = { | ||
contextTypes: { | ||
getStore: React.PropTypes.func, | ||
executeAction: React.PropTypes.func | ||
}, | ||
// @todo: remove child context and encourage use of the FluxibleComponent | ||
childContextTypes: { | ||
getStore: React.PropTypes.func, | ||
executeAction: React.PropTypes.func | ||
}, | ||
/** | ||
* Provides the current context as a child context | ||
* @method getChildContext | ||
*/ | ||
getChildContext: function(){ | ||
var context = {}; | ||
Object.keys(FluxibleMixin.childContextTypes).forEach(function (key) { | ||
context[key] = (this.props.context && this.props.context[key]) || this.context[key]; | ||
}, this); | ||
return context; | ||
}, | ||
/** | ||
* Registers staticly declared listeners | ||
* @method componentDidMount | ||
*/ | ||
componentDidMount: function componentDidMount() { | ||
this.listeners = []; | ||
var self = this; | ||
// Register static listeners | ||
this.getListeners().forEach(function(listener) { | ||
self._attachStoreListener(listener); | ||
}); | ||
}, | ||
/** | ||
* Calls an action | ||
* @method executeAction | ||
*/ | ||
executeAction: function executeAction() { | ||
var context = this.props.context || this.context; | ||
if (!context || !context.executeAction) { | ||
throw new Error('executeAction was called but no context was provided. Pass the fluxible' + | ||
'context via a `context` prop or via React\'s context.'); | ||
if ('production' !== process.env.NODE_ENV) { | ||
var objectAssign = require('object-assign'); | ||
FluxibleMixin = objectAssign({}, FluxibleMixin, { | ||
componentWillMount: function () { | ||
console.warn( | ||
"require('fluxible').FluxibleMixin has been moved out of the " + | ||
"default exports for Fluxible. Please use " + | ||
"require('fluxible/addons/FluxibleMixin') instead." | ||
); | ||
} | ||
return context.executeAction.apply(context, arguments); | ||
}, | ||
}); | ||
} | ||
/** | ||
* Gets a store instance from the context | ||
* @param {Function|String} store The store to get | ||
* @returns {Object} | ||
* @method getStore | ||
*/ | ||
getStore: function (store) { | ||
var storeInstance = store; | ||
if ('object' !== typeof storeInstance) { | ||
var context = this.props.context || this.context; | ||
if (!context) { | ||
throw new Error('storeListener mixin was called but no context was provided for getting the store.' + | ||
'Pass the fluxible context via a `context` prop or via React\'s context.'); | ||
} | ||
storeInstance = context.getStore(store); | ||
} | ||
return storeInstance; | ||
}, | ||
/** | ||
* Gets from the context all store instances required by this component | ||
* @returns {Object} | ||
* @method getStores | ||
*/ | ||
getStores: function() { | ||
var storesByName = this.getListeners().reduce(function (accum, listener) { | ||
accum[listener.store.constructor.storeName] = listener.store; | ||
return accum; | ||
}, {}); | ||
return Object.keys(storesByName).map(function(storeName) { | ||
return storesByName[storeName]; | ||
}); | ||
}, | ||
/** | ||
* Gets a store-change handler from the component | ||
* @param {Function|String} handler The handler to get | ||
* @returns {Function} | ||
* @method getHandler | ||
*/ | ||
getHandler: function (handler) { | ||
if ('string' === typeof handler) { | ||
handler = this[handler]; | ||
} | ||
if (!handler) { | ||
throw new Error('storeListener attempted to add undefined handler. Make sure handlers are actually exist.'); | ||
} | ||
return handler; | ||
}, | ||
/** | ||
* Gets a listener descriptor for a store and store-change handler | ||
* @param {Function|String} store Store | ||
* @param {Function|String} handler The handler function or method name | ||
* @returns {Object} | ||
* @method getListener | ||
*/ | ||
getListener: function(store, handler) { | ||
handler = this.getHandler(handler); | ||
var storeInstance = this.getStore(store); | ||
return { | ||
store: storeInstance, | ||
handler: handler | ||
}; | ||
}, | ||
/** | ||
* Gets all store-change listener descriptors from the component | ||
* @returns {Object} | ||
* @method getListeners | ||
*/ | ||
getListeners: function() { | ||
var self = this; | ||
var storeListeners = self.constructor.storeListeners; // Static property on component | ||
// get static listeners | ||
if (storeListeners) { | ||
if (Array.isArray(storeListeners)) { | ||
return storeListeners.map(function(store) { | ||
return self.getListener(store, DEFAULT_CHANGE_HANDLER); | ||
}); | ||
} else { | ||
return Object.keys(storeListeners).reduce(function (accum, handlerName) { | ||
var stores = storeListeners[handlerName]; | ||
if (!Array.isArray(stores)) { | ||
stores = [stores]; | ||
} | ||
return accum.concat(stores.map(function (store) { | ||
return self.getListener(store, handlerName); | ||
})); | ||
}, []); | ||
} | ||
} | ||
return []; | ||
}, | ||
/** | ||
* If provided with events, will attach listeners to events on EventEmitter objects(i.e. Stores) | ||
* If the component isn't mounted, events aren't attached. | ||
* @param {Object} listener | ||
* @param {Object} listener.store Store instance | ||
* @param {Object} listener.handler Handler function or method name | ||
* @method _attachStoreListener | ||
* @private | ||
*/ | ||
_attachStoreListener: function _attachStoreListener(listener) { | ||
if (this.isMounted && !this.isMounted()) { | ||
throw new Error('storeListener mixin called listen when component wasn\'t mounted.'); | ||
} | ||
listener.store.addChangeListener(listener.handler); | ||
this.listeners.push(listener); | ||
}, | ||
/** | ||
* Removes all listeners | ||
* @method componentWillUnmount | ||
*/ | ||
componentWillUnmount: function componentWillUnmount() { | ||
this.listeners.forEach(function (listener) { | ||
listener.store.removeChangeListener(listener.handler); | ||
}); | ||
this.listeners = []; | ||
} | ||
}; | ||
module.exports = FluxibleMixin; |
{ | ||
"name": "fluxible", | ||
"version": "0.3.3", | ||
"version": "0.4.0", | ||
"description": "A pluggable container for isomorphic flux applications", | ||
@@ -11,10 +11,11 @@ "main": "index.js", | ||
"scripts": { | ||
"test": "mocha tests/unit/ --recursive --reporter spec", | ||
"cover": "istanbul cover --dir artifacts -- _mocha tests/unit/ --recursive --reporter spec", | ||
"test": "mocha tests/unit/ --recursive --compilers js:babel/register --reporter spec", | ||
"cover": "istanbul cover --dir artifacts -- _mocha tests/unit/ --recursive --compilers js:babel/register --reporter spec", | ||
"lint": "jshint" | ||
}, | ||
"dependencies": { | ||
"async": "^0.9.0", | ||
"debug": "^2.0.0", | ||
"dispatchr": "^0.2.5", | ||
"dispatchr": "^0.3.1", | ||
"es6-promise": "^2.0.1", | ||
"is-promise": "^2.0.0", | ||
"object-assign": "^2.0.0", | ||
@@ -27,8 +28,6 @@ "setimmediate": "^1.0.2" | ||
"devDependencies": { | ||
"babel": "^5.0.2", | ||
"chai": "^2.0.0", | ||
"cheerio": "^0.18.0", | ||
"connect-livereload": "^0.5.2", | ||
"coveralls": "^2.11.1", | ||
"flux-router-component": "^0.6.0", | ||
"grunt": "^0.4.5", | ||
"istanbul": "^0.3.2", | ||
@@ -39,6 +38,4 @@ "jsdom": "^3.1.2", | ||
"mockery": "^1.4.0", | ||
"node-jsx": "^0.12.4", | ||
"precommit-hook": "1.0.x", | ||
"react": "0.13.x", | ||
"supertest": "^0.15.0" | ||
"react": "0.13.x" | ||
}, | ||
@@ -45,0 +42,0 @@ "author": "Michael Ridgway <mridgway@yahoo-inc.com>", |
@@ -24,10 +24,10 @@ # Fluxible | ||
* Singleton-free for [server rendering](https://github.com/yahoo/fluxible/blob/master/docs/api/server-rendering.md) | ||
* [Server dehydration](https://github.com/yahoo/fluxible/blob/master/docs/guides/server-rendering.md#dehydrationrehydration) for client bootstrapping | ||
* Singleton-free for server rendering | ||
* [Store](https://github.com/yahoo/fluxible/blob/master/docs/api/Stores.md) dehydration for client bootstrapping | ||
* Stateless async [actions](https://github.com/yahoo/fluxible/blob/master/docs/api/Actions.md) | ||
* React [mixin](https://github.com/yahoo/fluxible/blob/master/docs/api/FluxibleMixin.md) and [component](https://github.com/yahoo/fluxible/blob/master/docs/api/FluxibleComponent.md) for easy integration | ||
* Enforcement of Flux flow - restricted access to the [Flux context](https://github.com/yahoo/fluxible/blob/master/docs/api/FluxibleContext.md) from within components | ||
* Higher order [components](https://github.com/yahoo/fluxible/blob/master/docs/api/Components.md) for easy integration | ||
* Enforcement of Flux flow - restricted access to the [Flux interface](https://github.com/yahoo/fluxible/blob/master/docs/api/FluxibleContext.md) from within components | ||
* [Pluggable](https://github.com/yahoo/fluxible/blob/master/docs/api/Plugins.md) - add your own interfaces to the Flux context | ||
* Updated for React 0.13 | ||
## Extras | ||
@@ -39,18 +39,17 @@ | ||
* [Isomorphic Data Services](https://github.com/yahoo/fluxible-plugin-fetchr) | ||
## Usage | ||
```js | ||
var Fluxible = require('fluxible'); | ||
var React = require('react'); | ||
import Fluxible from 'fluxible'; | ||
import React from 'react'; | ||
import {connectToStores, createStore, provideContext} from 'fluxible/addons'; | ||
// Action | ||
var action = function (context, payload, done) { | ||
context.dispatch('FOO_ACTION', payload); | ||
done(); | ||
const action = (actionContext, payload) => { | ||
actionContext.dispatch('FOO_ACTION', payload); | ||
}; | ||
// Store | ||
var createStore = require('fluxible/addons').createStore; | ||
var Store = createStore({ | ||
const FooStore = createStore({ | ||
storeName: 'FooStore', | ||
@@ -63,3 +62,3 @@ handlers: { | ||
}, | ||
fooHandler: function (payload) { | ||
fooHandler: function (payload) { | ||
this.foo = payload; | ||
@@ -75,26 +74,22 @@ }, | ||
// Component | ||
var App = React.createClass({ | ||
mixins: [Fluxible.FluxibleMixin], // Calls onChange when storeListeners emit change | ||
statics: { | ||
storeListeners: [Store] | ||
}, | ||
getInitialState: function () { | ||
return this.getStore(Store).getState(); | ||
}, | ||
onChange: function () { | ||
this.setState(this.getStore(Store).getState()); | ||
}, | ||
render: function () { | ||
return <span>{this.state.foo}</span> | ||
class App extends React.Component { | ||
render() { | ||
return <span>{this.props.foo}</span> | ||
} | ||
}); | ||
} | ||
App = provideContext(connectToStores(App, [FooStore], { | ||
FooStore(store) { | ||
return store.getState(); | ||
} | ||
})); | ||
// App | ||
var fluxibleApp = new Fluxible({ | ||
component: App | ||
const app = new Fluxible({ | ||
component: App, | ||
stores: [FooStore] | ||
}); | ||
fluxibleApp.registerStore(Store); | ||
// Bootstrap | ||
var context = fluxibleApp.createContext(); | ||
const context = app.createContext(); | ||
context.executeAction(action, 'bar', function () { | ||
@@ -101,0 +96,0 @@ console.log(React.renderToString(context.createElement())); |
module.exports = { | ||
createMockActionContext: require('./MockActionContext'), | ||
createMockComponentContext: require('./MockComponentContext') | ||
createMockActionContext: require('./createMockActionContext'), | ||
createMockComponentContext: require('./createMockComponentContext') | ||
}; |
@@ -7,39 +7,4 @@ /** | ||
var dispatchr = require('dispatchr'); | ||
module.exports = function createMockActionContext(Dispatcher) { | ||
var Dispatcher = Dispatcher || dispatchr(); | ||
function MockActionContext (dispatcher) { | ||
this.Dispatcher = Dispatcher; | ||
this.dispatcher = dispatcher || new Dispatcher(); | ||
this.executeActionCalls = []; | ||
this.dispatchCalls = []; | ||
} | ||
MockActionContext.registerStore = Dispatcher.registerStore; | ||
MockActionContext.prototype.getStore = function (name) { | ||
return this.dispatcher.getStore(name); | ||
}; | ||
MockActionContext.prototype.dispatch = function (name, payload) { | ||
this.dispatchCalls.push({ | ||
name: name, | ||
payload: payload | ||
}); | ||
this.dispatcher.dispatch(name, payload); | ||
}; | ||
MockActionContext.prototype.executeAction = function (action, payload, callback) { | ||
this.executeActionCalls.push({ | ||
action: action, | ||
payload: payload | ||
}); | ||
action(this, payload, callback); | ||
}; | ||
MockActionContext.Dispatcher = Dispatcher; | ||
return MockActionContext; | ||
}; | ||
throw new Error("`require('fluxible/utils/MockActionContext')` has been removed in " + | ||
"favor of `require('fluxible/utils').createMockActionContext; See " + | ||
"https://github.com/yahoo/fluxible/pulls/99 for details.`"); |
@@ -7,33 +7,4 @@ /** | ||
var dispatchr = require('dispatchr'); | ||
var createMockActionContext = require('./MockActionContext'); | ||
function noop () {} | ||
module.exports = function createMockComponentContextClass(Dispatcher) { | ||
Dispatcher = Dispatcher || dispatchr(); | ||
var MockActionContext = createMockActionContext(Dispatcher); | ||
function MockComponentContext () { | ||
this.dispatcher = new Dispatcher(); | ||
this.executeActionCalls = []; | ||
this.getStore = this.getStore.bind(this); | ||
this.executeAction = this.executeAction.bind(this); | ||
} | ||
MockComponentContext.prototype.getStore = function (name) { | ||
return this.dispatcher.getStore(name); | ||
}; | ||
MockComponentContext.prototype.executeAction = function (action, payload) { | ||
this.executeActionCalls.push({ | ||
action: action, | ||
payload: payload | ||
}); | ||
action(new MockActionContext(this.dispatcher), payload, noop); | ||
}; | ||
MockComponentContext.Dispatcher = Dispatcher; | ||
MockComponentContext.registerStore = Dispatcher.registerStore; | ||
return MockComponentContext; | ||
}; | ||
throw new Error("`require('fluxible/utils/MockComponentContext')` has been removed in " + | ||
"favor of `require('fluxible/utils').createMockComponentContext; See " + | ||
"https://github.com/yahoo/fluxible/pulls/99 for details.`"); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
91783
11
40
987
7
102
3
1
+ Addedes6-promise@^2.0.1
+ Addedis-promise@^2.0.0
+ Addeddispatchr@0.3.3(transitive)
+ Addedes6-promise@2.3.0(transitive)
+ Addedeventemitter3@1.2.0(transitive)
+ Addedis-promise@2.2.2(transitive)
- Removedasync@^0.9.0
- Removedasync@0.9.2(transitive)
- Removeddispatchr@0.2.14(transitive)
Updateddispatchr@^0.3.1