Skip to content

Instantly share code, notes, and snippets.

@simenbrekken
Last active August 29, 2015 14:19
Show Gist options
  • Select an option

  • Save simenbrekken/10078b68afe5eba497b8 to your computer and use it in GitHub Desktop.

Select an option

Save simenbrekken/10078b68afe5eba497b8 to your computer and use it in GitHub Desktop.
Relay-style higher-order React components backed by Reflux
var Reflux = require('reflux')
var axios = require('axios')
var CategoryStore = Reflux.createStore({
init: function() {
this.items = null
},
list: function() {
var items = this.items
if (!items) {
axios
.get('/categories')
.then(function(res) {
this.items = res.data
this.trigger()
}.bind(this))
}
return items
}
})
module.exports = CategoryStore
var React = require('react')
var debug = require('debug')('storefront:create-container')
var lodash = require('lodash')
var shallowEqual = require('react/lib/shallowEqual')
function createContainer(Component, options) {
var queries = options.queries || {}
var queryParams = options.queryParams || {}
function getQuery(key, queryParams, props) {
var query = queries[key]
return query.get(queryParams, props)
}
function getAllQueries(queryParams, props) {
return lodash.reduce(queries, function(result, query, key) {
result[key] = getQuery(key, queryParams, props)
return result
}, {})
}
return React.createClass({
displayName: Component.displayName + 'Container',
propTypes: {
queryParams: React.PropTypes.object,
loader: React.PropTypes.component
},
getInitialState: function() {
return {}
},
setStateFromQueries: function(props) {
var queryParams = this.queryParams
var state = lodash.reduce(queries, function(query) {
return query.get(queryParams, props)
}, {})
this.replaceState(state)
},
setQueryParams: function(queryParams) {
var nextQueryParams = lodash.assign({}, this.queryParams, queryParams)
if (!shallowEqual(nextQueryParams, this.queryParams)) {
this.queryParams = nextQueryParams;
this.replaceState(getAllQueries(nextQueryParams, this.props))
}
},
onQueryChange: function(key) {
var state = {}
state[key] = getQuery(key, this.queryParams, this.props)
this.setState(state)
},
componentWillMount: function() {
this.queryParams = lodash.assign({}, queryParams, this.props.queryParams)
this.replaceState(getAllQueries(this.queryParams, this.props))
},
componentDidMount: function() {
this.subscriptions = lodash.map(queries, function(query, key) {
return query.listenTo.listen(lodash.partial(this.onQueryChange, key))
}, this)
},
componentWillReceiveProps: function(nextProps) {
if (!shallowEqual(nextProps, this.props)) {
this.replaceState(getAllQueries(this.queryParams, nextProps))
}
},
componentWillUnmount: function() {
if (this.subscriptions) {
lodash.forEach(this.subscriptions, function(unsubscribe) {
unsubscribe()
})
}
},
shouldComponentUpdate: function(nextProps, nextState) {
return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);
},
render: function() {
var requiredQueries = lodash.keys(queries)
var loadedQueries = lodash.keys(lodash.pick(this.state, lodash.identity))
var loading = lodash.difference(requiredQueries, loadedQueries)
if (loading.length) {
debug('%s waiting for %s', this.constructor.displayName, loading.join(', '))
return options.loader || null
}
debug('%s done loading', this.constructor.displayName)
var props = lodash.assign({}, this.props, this.state, {
queryParams: this.queryParams,
setQueryParams: this.setQueryParams
})
return React.createElement(Component, props)
}
})
}
module.exports = createContainer
var React = require('react')
var CategoryStore = require('./CategoryStore')
var Grid = require('./FrontpageGrid')
var Navigation = require('./FrontpageNavigation')
var Loader = require('./Loader')
var createContainer = require('./createContainer')
var Frontpage = React.createClass({
render: function() {
return (
<main className="frontpage-section">
<Navigation categories={this.props.categories} />
<Grid />
</main>
)
}
})
module.exports = createContainer(Frontpage, {
queries: {
categories: {
listenTo: CategoryStore,
get: function() {
return CategoryStore.list()
}
}
},
loader: <Loader />
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment