Suggestion for global context

(Johnnysprinkles) #1

tl;dr Let’s add a 4th parameter to ReactDOM.render() which is static global context.

I’ve used React at my previous job (Uber) and my current job (OfferUp) and I love it, but one thing I’ve always stumbled on is how to have request-scoped constant global data available to all components.

Here’s some example of data we’d want available for all components at any depth:

  • css color constants, these are used in LESS code but also available to JS for inline CSS in JSX, looks something like:

    css: {
      blueColor: "#3d98d2"
      darkBlueColor: "#225e87"
      darkGreenColor: "#009770"
  • manifest of asset locations on CDN, e.g.

    manifest: {
      "images/chevron-up.png": "web/images/chevron-up.9cd7cf64.png",
      "images/default-avatar-small.png": "web/images/default-avatar-small.49fe6650.png",
      "images/download2@2x.png": "web/images/download2@2x.f45ffc88.png",
  • Authenticated user object created by middleware if user is signed in, such as:

    authUser: {
      id: 12345,
      name: "John",
      avatar: "",
  • User location object created by middleware based on geocoded IP address, e.g.

    location: {
      display: "Bellevue, WA",
      latitude: 47.594715,
      longitude: -122.192886

So we pass these 4 things down deeply in many places. The first two things are not request specific so they could simply be made available in an import. But the last two are, which isn’t a problem on the client since the whole execution environment is request-specific, but this is an isomorphic app. Making request-specific information available to all components on the Node side… how to do that? Maybe use context?


What an incredible amount of boilerplate! I’d guess that 99% of the use cases are for global context, i.e. not having subtrees with different context. And that 99% of the use cases are for constant data. What if we had a system that only addressed those needs and was vastly simpler, avoiding the need for a top-level Provider component, and for each child component to declare what context it’s interested in receiving. What if just had context that went everywhere automatically? What if it was just like:

class Homepage extends React.Component {
  render() {
      <Thing />
        <Whatever />
        <Salad />
class Salad extends React.Component {
  render() {
    <div>Dressing: {this.context.dressing}</div>
  <Homepage />,
  {dressing: 'ranch', zipcode: '98103'}

And now every component gets that context (either mixed into its props, or in this.context, doesn’t matter) no matter what depth it’s at?

Instead of giving root props to the root component and having it be responsible for passing things down further via context, can’t we move that job up to the render/hydrate level? Why should one have to mess around with their React components so much just to pipe global data through?

This is my dream. Maybe there’s a better way to achieve my end goal, if there is let me know, but wanted to see if this seems like a good idea or not. Thanks!

(Troy Rhinehart) #2

context is a great solution, and I use it a lot for theming and state that is not considered global. I’ve rarely ran into an issue where specifying contextTypes was too much of a burden, but there’s nothing stopping you from just creating a helper class.

class ContextAwareComponent extends React.Component {
  static contextTypes = {
    dressing: PropTypes.string

and using it on your inner classes

class Salad extends ContextAwareComponent {
  render() {
    return <div>Dressing: { this.context.dressing }</div>;

or stateless functions

function StatelessSalad(props, context) {
  return <div>Dressing: { this.context.dressing }</div>;
StatelessSalad.contextTypes = ContextAwareComponent.contextTypes;