Skip to content

Instantly share code, notes, and snippets.

@nkohari
Created June 23, 2014 00:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nkohari/be5d1f62c25b6bd17787 to your computer and use it in GitHub Desktop.
Save nkohari/be5d1f62c25b6bd17787 to your computer and use it in GitHub Desktop.
Proof-of-concept of AngularJS-inspired dependency injection in React.js
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)
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
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
@nkohari
Copy link
Author

nkohari commented Jun 23, 2014

It might help to point out that the forge-di dependency in this is my DI framework here: https://github.com/nkohari/forge

@robashton
Copy link

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?)

@nkohari
Copy link
Author

nkohari commented Jun 23, 2014

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