Eric Elliott
3 min readMay 31, 2015

--

What do you mean by “does not work?” Could you reproduce the problem on CodePen.IO? As I understand context, you should still be able to provide `.getChildContext()` as a method on your components.

I confess I don’t use context. It’s an undocumented feature, and its implementation may change before React 1.0 lands (and did change in .12 -> .13), so I’ve been holding off on the idea of experimenting with it. I do see some valid use-cases, though. Facebook uses it to pass a viewer to entire component subtrees. However, there’s more than one way to skin a cat, as you’ll see.

As for passing props quickly, I do that in a couple ways — first, I use container components which have some interesting conventions:

  • All my UI components don’t know anything about the app. All they know are their props and actions.
  • I use container components to provide app context. Container components are responsible for translating the generic UI component’s actions and props into actions and query subscriptions that make sense for the particular app the components are being used in. Think of container components as app adapters that generic components get plugged into. The result? Components stay completely app independent and reusable, but they’re also easy to recompose in different configurations for different needs and apps.
  • All my components know about `props.actions`, so all component actions get passed through the hierarchy. Every component relays actions to children. Think of actions as user intents. Not what they clicked on, or the UI element they’re manipulating, but what the user is actually trying to accomplish with those actions. So instead of “clicked delete button,” a corresponding action might be `deleteListItem()`. I call actions as functions in components, but they get translated by the app to objects like they’re described in the Flux architecture. To clarify the difference between the functions and the objects, I refer to action objects as commands (inspired by the command pattern). An observable stream of those command objects is subscribed to by the store, and that’s where the actual data updates happen. Components never directly manipulate shared state in my apps.
  • I use a single store and all data entities are available as root nodes in the store. Data entities all have entity types which can be used to query. All container components know how to subscribe to queries for the data they need. Data changes are made available as observable streams. This will get even more powerful when Relay lands. Container components know how to translate query results into props for their child components.
  • I export factories for all components, rather than directly exporting the components themselves. This provides two advantages: 1) I always pass `React` in on an `options` object, so components don’t need to import a potentially conflicting `React` or assume that React is available as a global. 2) You can relay anything you want through all components in the `options` hash, and all components will have access to it.

An important note: I treat everything passed through `options` as immutable. In other words, I treat `options` like a broadcast-only medium and relay all state changes through actions so that data flow is always uni-directional in my apps.

When I’ve had more time to live with this architecture, I’ll write a thorough blog post with working examples. I’m hoping that Relay will land in the meantime because I expect this architecture to change and take advantage of the new capabilities with GraphQL and Relay.

For readers who haven’t seen the article this response is about, read “Baby’s First Reaction” for a working example of the component factory and actions described above.

--

--