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

JavascriptFacebookReactjs

Javascript Problem Overview


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: '[email protected]',
  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?

Javascript Solutions


Solution 1 - Javascript

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....

Solution 2 - Javascript

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.

Solution 3 - Javascript

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.

Solution 4 - Javascript

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}/>
}

Solution 5 - Javascript

There is Reactn https://www.npmjs.com/package/reactn
You use this.global and this.setGlobal to get and set the global state same as you do with the local state.
To be able to do so you only need to
import React from 'reactn';

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBrad ParksView Question on Stackoverflow
Solution 1 - JavascriptBrad ParksView Answer on Stackoverflow
Solution 2 - JavascriptSteve TaylorView Answer on Stackoverflow
Solution 3 - JavascriptmukeshmandiwalView Answer on Stackoverflow
Solution 4 - JavascriptBoxerBucksView Answer on Stackoverflow
Solution 5 - JavascriptJuan LanusView Answer on Stackoverflow