marionette-redux
v1.0.2
Published
Marionette and Backbone bindings for Redux
Maintainers
Readme
Marionette Redux
Marionette and Backbone bindings for Redux.
It's like React Redux, but for Marionette and Backbone.
Marionette Redux allows you to connect any Marionette or Backbone "component" to a Redux store.
Why Use This Library?
Predictability
Marionette Redux introduces to a Marionette application a lifecycle that allows for deterministic DOM updates – consistent at first render and for any subsequent store updates (or component state changes) after the first render.
Migrating to React
If you've decided to migrate, Marionette Redux allows you to leverage Redux as a central data store to share app state between your React and Marionette components.
Examples:
How Does It Work?
componentWillUpdate will execute when a display component (Marionette.View or Marionette.Behavior) first renders. This is where you put your DOM manipuation code.
A connected component's mapStateToProps will execute whenever the Redux store state changes. If the return object of display component's mapStateToProps differs from the last result, componentWillUpdate will execute.
Thus, you can set up components to always rely on the same set of values to determine their DOM state. This means that your view's can execute the same callstack on first render and for any Redux store changes.
Installation
npm install --save marionette-reduxUsage
connect
Below is an example of a Marionette.View that has been "connected" to a Redux store. The following code could also be applied to a Marionette.Behavior.
var ConnectedView = MarionetteRedux.connect()(Marionette.View.extend({
store: store,
mapStateToProps: function(state) {
return {
isActive: state.isActive
}
},
componentWillUpdate: function() {
this.$el.toggleClass('active', this.props.isActive);
}
}));In this example, store is a property on the component, but connect will also look to window.store as a last resort. window.store can thus act similarly to React Redux's "Provider".
mixin
While connect is the recommended approach, Marionette Redux can also be used as a mixin.
Marionette.View.extend(MarionetteRedux.mixin);Mappings
Mappings work the same as in React Redux. A change to the Redux store will result in this callback being executed on any "connected" components.
mapStateToProps
mapStateToProps can be a property on the component itself.
var ConnectedView = MarionetteRedux.connect()(Marionette.View.extend({
mapStateToProps: function(state) {
return {
isActive: state.isActive
}
}
}));Or it can be provided to connect as the first argument.
function mapStateToProps(state) {
return {
isActive: state.isActive
}
}
var ConnectedView = MarionetteRedux.connect(mapStateToProps)(Marionette.View.extend({…}));mapDispatchToProps
mapDispatchToProps can also be a property on the component.
var ConnectedView = MarionetteRedux.connect()(Marionette.View.extend({
mapDispatchToProps: function(dispatch) {
return {
dispatchMyEvent: function() {
dispatch({
type: 'MY_EVENT'
});
}
}
},
events: {
click: 'handleClick'
},
handleClick: function() {
this.props.dispatchMyEvent();
}
}));Or it can provided to connect as the second argument.
var ConnectedView = MarionetteRedux.connect(null, mapDispatchToProps)(Marionette.View.extend({…}));Lifecycle
componentWillReceiveProps
This function is similar to React's componentWillReceiveProps. It provides an opportunity to execute any side effect functions before execution of componentWillUpdate.
Note: If the component is not a display component, meaining it is a Backbone.Model or Backbone.Collection, componentWillReceiveProps will still execute, however componentWillUpdate WILL NOT.
componentWillUpdate
This library ecourages the use of componentWillUpdate to ensure predictability of DOM state – one of the great things about React.
As demonstrated below, componentWillUpdate can be used to execute code that you want to run when a component is first rendered and after any subsequent changes to a component's props or state.
var ConnectedView = MarionetteRedux.connect()(Marionette.View.extend({
store: store,
mapStateToProps: function(state) {
return {
isActive: state.isActive
}
},
componentWillUpdate: function() {
this.$el.toggleClass('active', this.props.isActive);
}
}));State
If you prefer more granular control over store updates, we've provided state to components as well.
setState, getState, state, and getInitialState are all available for getting and setting state.
State works exactly the same as Marionette's modelEvents listeners, using the stateEvents object to define listeners:
var ConnectedView = MarionetteRedux.connect()(Marionette.View.extend({
store: store,
getInitialState: function() {
return: {
isActive: false
}
},
stateEvents: {
'change:isActive': 'onIsActiveChange'
},
onIsActiveChange: function(view, isActive) {
this.$el.toggleClass('active', isActive);
},
mapStateToProps: function(state) {
return {
isActive: state.active === this.model.id
}
},
componentWillReceiveProps: function(update) {
this.setState({
isActive: update.isActive
});
},
}));As with changes to props, changes to a display component's state will execute componentWillUpdate.
Backbone
You also have the option to connect a Backbone.Model or Backbone.Collection.
Model
function mapStateToProps(state) {
return {
currency: state.currency
}
}
var Model = Backbone.Model.extend({
store: store,
initialize: function() {
// update the store on changes
this.on('update', function() {
store.dispatch({
type: 'MODEL_UPDATE',
data: this.toJSON()
});
})
},
componentWillReceiveProps: function(update) {
this.set({
currency: update.currency
})
}
});
var ConnectedModel = MarionetteRedux.connect(mapStateToProps)(Model);Collection
var Collection = Backbone.Collection.extend({
store: store,
initialize: function() {
// update the store on changes
this.on('update', function() {
store.dispatch({
type: 'COLLECTION_UPDATE',
data: this.toJSON()
});
})
}
});
var ConnectedCollection = MarionetteRedux.connect()(Collection);License
MIT
