Jason Node Jason Node - 2 months ago 10
React JSX Question

In React, what is the proper way of injecting shared state into components that are not in a parent-child relationship?

The problem I ran into is this: I want to have multiple buttons that open the same modal, and depending on which button is pressed, the modal will have different content.

The buttons are placed in a Component and the modal is placed in another one (also, they are not in a parent-child relationship).

I have a "state object" that saves info about which button was clicked and whether the modal is opened or closed. This object needs to be read AND modified by BOTH components.

In Angular, I would create a Service that manages the state of the buttons and the modal by injecting the "state object" into both components.

How would I solve this in React?

(I read somewhere that this can be accomplished by using Redux, but at the moment my app doesn't implement the flux architecture and I'd need a solution that doesn't require flux/redux)

Answer

The idea of Redux is to have the state very high up in the component tree and you can simulate this idea by shifting the state higher up into the component tree.

  1. Find a common ancestor of these components (preferably lowest one) that you want to read/modify the object, and save the object as state in that component. There definitely will be a common ancestor (the root) for every pair of components which are not root elements.
  2. This common ancestor should define a method that is passed down into these components as props so that these child components can call the actions and modify the state within the ancestor.

Some example code is shown below. Let me know if you need further clarification.

class Ancestor extends React.Component {
  constructor(props) {
    super(props);
    this.state = { object: null };
  }

  someMethod(data) {
    this.setState({
      object: data
    });
  }

  render() {
    return (
      <div>
        <div>
          <Button clickHandler={this.someMethod.bind(this)}/>
          <Button clickHandler={this.someMethod.bind(this)}/>
        </div>
        <Modal data={this.state.object} someProp={this.someMethod.bind(this)}/>
      </div>
    )
  }
}

class Button extends React.Component {
  doSomething() {
    this.props.clickHandler(someData);
  }

  render() {
    return (
      <button onClick={this.doSomething.bind(this)}/>Button</button>
    );
  }
}
Comments