ReactJS - how to pass "global" data to deeply nested child components?

How do people typically approach having "global" data in a React application?

For example, say I have the following data for a user once they're logged into my app.

user: {
  email: 'test@user.com',
  name: 'John Doe'
}

This is data that almost any component in my app might like to know about - so it could either render in a logged in or logged out state, or perhaps display the users email address if logged in.

From my understanding, the React way of accessing this data in a child component is for a top level component to own the data, and pass it to child components using properties, for example:

<App>
  <Page1/>
  <Page2>
    <Widget1/>
    <Widget2 user={user}/>
  </Page2>
</App>

But this seems unwieldy to me, as that would mean I'd have to pass the data through each composite, just to get it to the child that needed it.

Is there a React way of managing this type of data?

Note: This example is very simplified - I like to wrap intents up as composites so implementation details of entire UI features can be drastically changed as I see fit.

EDIT: I'm aware that by default, calling setState on my top level component would cause all child components to be re-rendered, and that in each child component I can render using whatever data I like (e.g. global data, not just state or props). But how are people choosing to notify only certain child components that they should be rendered?

Answers


Since I originally answered this question, it's become apparent to me that React itself doesn't support "global" data in any sense - it is truly meant to manage the UI and that's it. The data of your app needs to live somewhere else. Having said that, it does now support accessing global context data as detailed in this other answer on this page. This repo (Unstated) supposedly wraps up context in a nicer way, for those that are interested, and here's a good article by Kent Dodds on how the context api has evolved, and is now officially supported in React.

The context approach should only be used for truly global data. If your data falls into any other category, then you should do as follows:

  • Facebook themselves solve this problem using their own Flux library.
  • Mobx and Redux are similar to Flux, but seem to have more popular appeal. They do the same thing, but in a cleaner, more intuitive way.

I'm leaving my original edits to this answer below, for some history.

OLD ANSWER:


The best answer I've found for this so far are these 2 React mixins, which I haven't had a chance to try, but they sound like they'll address this problem:

https://github.com/dustingetz/react-cursor

and this similar library:

https://github.com/mquan/cortex

MAJOR NOTE: I think this is a job for Facebook's Flux, or something similar (which the above are). When the data flow gets too complex, another mechanism is required to communicate between components other than callbacks, and Flux and it's clones seem to be it....


Use the React Context Property This is specifically for passing global data sets down the chain without explicitly forwarding them. It does complicate your Component lifecycle functions though, and note the cautions offered on the page I've linked.


You can use the React Context API for passing global data down to deeply nested child components. Kent C. Dodds wrote an extensive article on it on Medium React’s ⚛️ new Context API. It'll help in getting a better understanding of how to use the API.


What's wrong with just passing data all the way down the component chain via rendering all children with {...restOfProps}?

render(){
  const {propIKnowAbout1, propIKnowAbout2, ...restOfProps} = this.props;
  return <ChildComponent foo={propIKnowAbout1} bar={propIKnowAbout2} {...restOfProps}/>
}

Need Your Help

Tracking Google Analytics Page Views in Angular2

javascript google-analytics angular

I have built a new site using Angular 2 as the front-end. As everything is done via push state, there are no page loads which typically trigger the Google Analytics code to send a page view to Goog...