8 no-Flux strategies for React component communication

November 21st, 2015
Updated: February 2nd, 2018

In React, one of the first big issues that comes up is figuring out how components should communicate with each other.

What's the best way to tell Component1 that Component2 was clicked?

If you start to dig a little, you'll get a ton of answers. Sooner or later Flux will be mentioned, which will only raise new questions.

Can I solve my communication issue with the Flux architecture? Is Flux necessary?

And yes, sometimes you can solve your communication issues with Flux, but no it is NOT necessary. None of the strategies in my list use Flux.

Some developers have a difficult time wrapping their head around Flux. Others find it doesn't fit well with the app they're building. Some developers use Flux just because it's popular - without realizing that simpler solutions exists.

So here are eight simple strategies for communicating between React components.

The 8 Strategies

Which strategy you use depends on the relationship between the components that should be communicating.

Use this as your table of contents to jump around and pick the strategy or strategies that apply to your use-case.

1. Props

Props are by far the most common way to transfer information between components. With props you can send data from a parent to a child.

Props are a central feature of React - you really can't use React without them. So if you aren't familiar with props yet then it's time to head back to the docs. Start with the page on components and props.

2. Instance Methods

Instance methods on the child component can be called by the parent using refs. This is another way to communicate with a child from a parent. Here's how:

  1. Write a class method in the child component. e.g. myFunc()
  2. Add a ref attribute that creates a reference to the child component in the parent component. e.g. ref={(foo) => { this.foo = foo; }}
  3. Call the child component method from the parent. e.g. this.foo.myFunc().
class TheChild extends React.Component {
  myFunc() {
    return "hello";
  }
}
class TheParent extends React.Component {
  render() {
    return (
      <TheChild
        ref={foo => {
          this.foo = foo;
        }}
      />
    );
  }

  componentDidMount() {
    var x = this.foo.myFunc();
    // x is now 'hello'
  }
}

3. Callback Functions

Strategies 1 & 2 cover passing data from a parent to a child, so how do you do the reverse? How do you send data from a child to its parent?

The simplest way is for the parent to pass a function to the child. The child can use that function to communicate with its parent.

The parent would pass a function to the child as a prop, like this:

<MyChild myFunc={this.handleChildFunc} />

And the child would call that function like so:

this.props.myFunc();

And don't forget that the child will need this function declared in its propTypes:

MyChild.propTypes = {
  myFunc: React.PropTypes.func
};

4. Event Bubbling

Event bubbling is not a React concept - it's a plain old DOM concept. Just like callback functions, this is a way to send data up from a child component to a parent component.

This works when you want a parent component to capture DOM events that originated in the DOM elements of its child components.

Here's an example of a parent component that will catch the onkeyup event in all of its child components:

class ParentComponent extends React.Component {
  render() {
    return (
      <div onKeyUp={this.handleKeyUp}>
        // Any number of child components can be added here.
      </div>
    );
  }

  handleKeyUp = (event) => {
    // This function will be called for the 'onkeyup'
    // event in any <input/> fields rendered by any of
    // my child components.
  }
}

5. Parent Component

If two components need to communicate, that may be a sign that they should be siblings.

If you wrap multiple components in a parent component, you can use some of the above strategies in combination to facilitate communication between them.

class ParentComponent extends React.Component {
  render() {
    return (
      <div>
        <SiblingA
          myProp={this.state.propA}
          myFunc={this.siblingAFunc}
        />
        <SiblingB
          myProp={this.state.propB}
          myFunc={this.siblingBFunc}
        />
      </div>
    );
  }
  // Define 'siblingAFunc' and 'siblingBFunc' here
}

6. Observer Pattern

The Observer Pattern is a software design pattern in which an object can send messages to multiple other objects.

No sibling or parent-child relationship is required to use this strategy.

Within the context of React, this would mean some components subscribe to receive particular messages and other components publish messages to those subscribers.

Components would typically subscribe in the componentDidMount method and unsubscribe in the componentWillUnmount method.

Here are 4 libraries that implement the Observer Pattern. The differences between them are subtle - EventEmitter is the most popular.

PubSubJS: "a topic-based publish/subscribe library written in JavaScript."
EventEmitter: "Evented JavaScript for the browser." It's actually an implementation of a library that already exists as part of nodejs core, but for the browser.
MicroEvent.js: "event emitter microlibrary - 20lines - for node and browser" mobx: "Simple, scalable state management."

7. Global Variables

Global variables are the duct tape of component communication. Don't use them on a spaceship 🚀.

On your personal projects & prototypes, why not do whatever works? Especially if it saves you some time.

I suggest using window. to make your use of global variables explicit. Just set window.x in the event handlers or lifecycle methods of one component, and read window.x in another component.

8. Context

Context works similarly to props, but instead of providing data to a single child, it can be used to provide data to an entire subtree. (Child of a child, child of a child of a child, and so on).

Context can only send data down the tree (parent to subtree). It can be paired with callback functions to pass data back up (subtree to parent).

Context was an undocumented feature of React until recently. Now you can find the documentation at reactjs.org/docs/context.html. The docs list some appropriate use-cases for context:

The best use cases for context are for implicitly passing down the logged-in user, the current language, or theme information. All of these might otherwise be true globals, but context lets you scope them to a single React subtree.

The docs also warn against overusing context:

If you have to use context, use it sparingly.

What now?

Pick the strategy or strategies that fit your app.