user1532043
user1532043

Reputation: 899

How to share states between different component while none of them are connected to each other by any parent child relation?

I am new to React and I find it interesting. I have a button and clicking on that button will set some state inside that class as true and based on that the title of the button will change. I want to change some other React component in some other class based on this state change. How can I do that ?

For example :

var Comp1 = React.createClass({
    getInitialState: function() {
        return { logged_in: false }
    },

    handleClick: function() {
        this.setState({logged_in: !this.state.logged_in});
    },

    render: function() {
        return <button onClick={this.handleClick}>
                   {this.state.logged_in ? "SIGN OUT" : "SIGN IN"} 
               </button>;
    }

})

Here is my second component which is rendered separately.

var Comp2 = React.createClass({
    render: function(){
        return <div>
                   {Comp1.state.logged_in ? "You are in" : "You need a login"}
               </div>;
    }
})

This is one component. I want to use the state of this component in another component either by passing the stat (though I am not using both the component in composite format, so they are independent by nature) or based on change in the state I can define another sate in the second component.

Upvotes: 1

Views: 146

Answers (1)

Kyeotic
Kyeotic

Reputation: 19857

You need to provide a shared object that can handle the state that these two objects represent. It is going to be easier to pick a standard model for doing this, like redux or flux, than to come up with your own. Learning one of these patterns is crucial to development in React. I personally recommend redux.

This is a very stripped down version of what Flux would look like. It is not intended to be a real solution, just to provide a glimpse of the pattern. If you just want to skip to the code, here is a codepen.

The shared object is typically referred to as a store. Stores hold state, and provide methods to subscribe to changes in that state. Mutating this state would usually by done by calling publishing an event with dispatcher that notifies the store, but for simplicity I have included a publish function on the store itself

let loginStore = {
  isLoggedIn: false,
  _subscribers: new Set(),
  subscribeToLogin(callback) {
    this._subscribers.add(callback);
  },
  unsubscribeToLogin(callback) {
    this._subscribers.delete(callback);
  },
  publishLogin(newState) {
    this.isLoggedIn = newState;
    this._subscribers.forEach(s => s(this.isLoggedIn));
  }
};

Once a pub/sub system is in place, the components will need to subcribe to it. The login button mutates this state, so it will also publish.

class LoginButton extends React.Component {
  constructor(...args) {
    super(...args);
    this.state = {isLoggedIn: loginStore.isLoggedIn};
  }
  update = (isLoggedIn) => {
    this.setState({isLoggedIn});
  }
  componentDidMount() {
    loginStore.subscribeToLogin(this.update);
  }
  componentDidUnmount(){
    loginStore.unsubscribeToLogin(this.update);
  }
  handleClick = () => {
    loginStore.publishLogin(!this.state.isLoggedIn);
  }
  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isLoggedIn ? "SIGN OUT" : "SIGN IN"} 
      </button>
    );
  }
}

class LoginHeader extends React.Component {
  constructor(...args) {
    super(...args);
    this.state = {isLoggedIn: loginStore.isLoggedIn};
  }
  update = (isLoggedIn) => {
    this.setState({isLoggedIn});
  }
  componentDidMount() {
    loginStore.subscribeToLogin(this.update);
  }
  componentDidUnmount(){
    loginStore.unsubscribeToLogin(this.update);
  }
  render() {
    return (
      <div>{this.state.isLoggedIn ? "You are in" : "You need a login"}</div>
    );
  }
}

You'll notice the second component does not refer to the state of the first component, but the state of the store. As you mentioned, since they do not have a reference to each other, and do not have a common parent, they cannot depend directly on each other for the loggedIn state.

Upvotes: 2

Related Questions