Skip to content

Commit

Permalink
Add AltNativeContainer
Browse files Browse the repository at this point in the history
  • Loading branch information
goatslacker committed Apr 15, 2015
1 parent edda162 commit 569b4c9
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
### Why you should be using Alt

* It is pure [flux](http://facebook.github.io/flux/docs/overview.html). Stores have no setters, the flow is unidirectional.
* Isomorphic! Run a flux setup on your server and then share the same code with the client.
* Isomorphic and works with react-native.
* Actively maintained and being used in production.
* Extremely [flexible](#flexibility) and unopinionated in how you use flux. Create traditional singletons or use dependency injection.
* It is [terse](https://github.com/goatslacker/alt#flux-minus-the-boilerplate). No boilerplate.
Expand Down
2 changes: 2 additions & 0 deletions components/AltContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ function getStateFromActionsProp(actions, props) {
}

var AltContainer = React.createClass({
displayName: 'AltContainer',

contextTypes: {
flux: React.PropTypes.object
},
Expand Down
159 changes: 159 additions & 0 deletions components/AltNativeContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/**
* AltNativeContainer.
*
* @see AltContainer
*/
var React = require('react-native')
var Subscribe = require('../mixins/Subscribe')
var assign = require('object-assign')

var View = React.View
var cloneWithProps = React.cloneWithProps

function getStateFromStore(store, props) {
return typeof store === 'function' ? store(props) : store.getState()
}

function getStateFromActionsProp(actions, props) {
return typeof actions === 'function' ? actions(props) : actions
}

var AltNativeContainer = React.createClass({
displayName: 'AltNativeContainer',

contextTypes: {
flux: React.PropTypes.object
},

getInitialState: function () {
if (this.props.stores && this.props.store) {
throw new ReferenceError('Cannot define both store and stores')
}

return this.reduceState(this.props)
},

componentWillReceiveProps: function (nextProps) {
this.destroySubscriptions()
this.setState(this.reduceState(nextProps))
this.registerStores(nextProps)
},

componentDidMount: function () {
this.registerStores(this.props)
},

componentWillUnmount: function () {
this.destroySubscriptions()
},

registerStores: function (props) {
Subscribe.create(this)

if (props.store) {
this.addSubscription(props.store)
} else if (props.stores) {
var stores = props.stores

if (Array.isArray(stores)) {
stores.forEach(function (store) {
this.addSubscription(store)
}, this)
} else {
Object.keys(stores).forEach(function (formatter) {
this.addSubscription(stores[formatter])
}, this)
}
}
},

destroySubscriptions: function () {
Subscribe.destroy(this)
},

getStateFromStores: function (props) {
if (props.store) {
return getStateFromStore(props.store, props)
} else if (props.stores) {
var stores = props.stores

// If you pass in an array of stores the state is merged together.
if (Array.isArray(stores)) {
return stores.reduce(function (obj, store) {
return assign(obj, getStateFromStore(store, props))
}.bind(this), {})

// if it is an object then the state is added to the key specified
} else {
return Object.keys(stores).reduce(function (obj, key) {
obj[key] = getStateFromStore(stores[key], props)
return obj
}.bind(this), {})
}
} else {
return {}
}
},

getStateFromActions: function (props) {
if (props.actions) {
return getStateFromActionsProp(props.actions, props)
} else {
return {}
}
},

reduceState: function (props) {
return assign(
{},
this.getStateFromStores(props),
this.getStateFromActions(props)
)
},

addSubscription: function (store) {
if (typeof store === 'object') {
Subscribe.add(this, store, this.altSetState)
}
},

altSetState: function () {
this.setState(this.reduceState(this.props))
},

getProps: function () {
var flux = this.props.flux || this.context.flux
return assign(
flux ? { flux: flux } : {},
this.state
)
},

shouldComponentUpdate: function () {
return this.props.shouldComponentUpdate
? this.props.shouldComponentUpdate(this.getProps())
: true
},

render: function () {
var children = this.props.children

// Custom rendering function
if (typeof this.props.render === 'function') {
return this.props.render(this.getProps())
}

// Does not wrap child in a div if we don't have to.
if (Array.isArray(children)) {
return React.createElement('div', null, children.map(function (child, i) {
return cloneWithProps(child, assign({ key: i }, this.getProps()))
}, this))
} else if (children) {
return cloneWithProps(children, this.getProps())
} else {
return React.createElement('div', this.getProps())
}
}
})

module.exports = AltNativeContainer
4 changes: 4 additions & 0 deletions docs/components/altContainer.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ The basic idea is that you have a container that wraps your component, the duty

AltContainer doesn't just wrap your dumb components into a high-performance store listener but it also serves as a jack-of-all-trades component where you can directly inject any dependencies into your components such as stores, actions, or the flux context.

## react-native

If you're using [`react-native`](http://www.reactnative.com/) then you'll want to use `AltNativeContainer`. It has the same API as AltContainer.

## Importing

To import `AltContainer`, you may do it like the following:
Expand Down

0 comments on commit 569b4c9

Please sign in to comment.