Skip to content

Instantly share code, notes, and snippets.

@christianalfoni
Created March 30, 2016 08:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save christianalfoni/c736ab1aec717e82a733a9264d131c52 to your computer and use it in GitHub Desktop.
Save christianalfoni/c736ab1aec717e82a733a9264d131c52 to your computer and use it in GitHub Desktop.
var React = require('react')
var mixin = require('./mixin.js')
module.exports = function (Component, paths) {
return React.createClass({
displayName: Component.name + 'Container',
mixins: [mixin],
componentWillReceiveProps: function (nextProps) {
this._update(null, nextProps);
},
getStatePaths: function (props) {
if (!paths) {
return {}
}
return typeof paths === 'function' ? paths(props) : paths
},
render: function () {
return React.createElement(Component, this.getProps())
}
})
}
var React = require('react')
var callbacks = []
var listener = false
var currentUpdateLoopId = null
module.exports = {
contextTypes: {
controller: React.PropTypes.object
},
componentWillMount: function () {
this.signals = this.context.controller.isServer ? {} : this.context.controller.getSignals()
this.modules = this.context.controller.isServer ? {} : this.context.controller.getModules()
var statePaths = this.getStatePaths ? this.getStatePaths(this.props) : {}
if (!Object.keys(statePaths).length) {
return
}
if (this.context.controller.isServer) {
return this._update()
}
if (!listener) {
listener = true
this.context.controller.on('change', function () {
var callbacksCount = callbacks.length
var nextCallbackIndex = -1
var runningLoopId = currentUpdateLoopId = Date.now() + (Math.random() * 10000).toFixed(0)
var runNextCallback = function () {
if (currentUpdateLoopId !== runningLoopId) {
return
}
nextCallbackIndex++
if (nextCallbackIndex === callbacksCount) {
return
}
callbacks[nextCallbackIndex](runNextCallback)
}
runNextCallback()
})
}
callbacks.push(this._update)
this._update()
},
componentWillUnmount: function () {
this._isUmounting = true
var statePaths = this.getStatePaths ? this.getStatePaths(this.props) : {}
if (Object.keys(statePaths).length) {
callbacks.splice(callbacks.indexOf(this._update), 1)
}
},
shouldComponentUpdate: function (nextProps, nextState) {
var propKeys = Object.keys(nextProps || {})
var stateKeys = Object.keys(nextState || {})
// props
for (var i = 0; i < propKeys.length; i++) {
if (this.props[propKeys[i]] !== nextProps[propKeys[i]]) {
return true
}
}
// State
for (var j = 0; j < stateKeys.length; j++) {
if (this.state[stateKeys[j]] !== nextState[stateKeys[j]]) {
return true
}
}
return false
},
getProps: function () {
var state = this.state || {}
var props = this.props || {}
var propsToPass = Object.keys(state).reduce(function (props, key) {
props[key] = state[key]
return props
}, {})
propsToPass = Object.keys(props).reduce(function (propsToPass, key) {
propsToPass[key] = props[key]
return propsToPass
}, propsToPass)
propsToPass.signals = this.signals
propsToPass.modules = this.modules
propsToPass.get = this.get // Uhm?
return propsToPass
},
_update: function (nextUpdate, props) {
if (this._isUmounting || this._lastUpdateLoopId === currentUpdateLoopId) {
return
}
this._lastUpdateLoopId = currentUpdateLoopId;
var statePaths = this.getStatePaths ? this.getStatePaths(props || this.props) : {}
var controller = this.context.controller
var newState = {}
newState = Object.keys(statePaths).reduce(function (newState, key) {
var value = controller.get(typeof statePaths[key] === 'string' ? statePaths[key].split('.') : statePaths[key])
newState[key] = value
return newState
}, newState)
if (nextUpdate) {
this.setState(newState, nextUpdate)
} else {
this.setState(newState)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment