Created
June 23, 2014 00:39
-
-
Save nkohari/be5d1f62c25b6bd17787 to your computer and use it in GitHub Desktop.
Proof-of-concept of AngularJS-inspired dependency injection in React.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Forge = require 'forge-di' | |
MonkeyPatcher = require './util/MonkeyPatcher' | |
Store = require './services/Store' | |
# Create the Forge and monkey-patch React.createClass() so it can inject dependencies. | |
forge = new Forge() | |
MonkeyPatcher.patchReact(forge) | |
# Register component bindings | |
forge.bind('store').to.type(Store) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
React = require 'react' | |
_ = require 'underscore' | |
createClass = React.createClass | |
MonkeyPatcher = {} | |
MonkeyPatcher.patchReact = (forge) -> | |
return unless React.createClass is createClass | |
React.createClass = (dependencies..., spec) -> | |
if _.isFunction(spec) | |
args = _.map dependencies, (dep) -> | |
if dep.name is 'forge' then forge else forge.get(dep) | |
spec = spec.apply(spec, args) | |
createClass(spec) | |
module.exports = MonkeyPatcher |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
React = require 'react' | |
{div} = React.DOM | |
# If the last argument to React.createClass() is a function, the arguments will be resolved | |
# via Forge and passed to the function, allowing their use inside the component's functions. | |
Test = React.createClass 'store', (store) -> | |
getInitialState: -> | |
store.get(@props.id) | |
render: -> | |
(div {}, "Sup, my name is #{@state.name}") | |
module.exports = Test |
I guess it depends on how militant you are about single responsibilities and loose coupling. For example, if you have components that receive new state via a web socket, you might want the "socket manager" piece to be injected via the closure rather than having it be a static dependency.
The way I've seen this typically solved is by putting state within the CommonJS module that's required, but that requires monkey-patching in order to test things, and can get unwieldy. In the end it's really a matter of choice, though.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Curious what this really adds over passing things via props.
To me the simplicity of React is that it's about top level data and control, if you're passing things around into components that aren't data your hierarchy is probably a bit weird. (I've been using React in projects for a few months and I've not yet come across a use case that would need the above?)