[React] Using session vars vs. props to communicate between components?

Putting Flux aside, I want to share data across React components, some of them not necessarily having a common direct parent. The way I am doing this right now is through Session variables like in the following example.

My question is: is it an efficient way to do that - ie. doesn’t it go against React best practices and break some of its magic?

Component_1 = React.createClass({
  mixins: [ReactMeteorData],
  getMeteorData() {
    return {
      someVar: Session.get('someVar')
    };
  },
  render() {
    return (
      <div>Input: {this.data.someVar}</div>
    );
  }
});

Component_2 = React.createClass({
  mixins: [ReactMeteorData],
  getMeteorData() {
    return {
      someVar: Session.get('someVar')
    };
  },
  handleInput() {
    var text = React.findDOMNode(this.refs.textInput).value.trim();
    Session.set('someVar', text);
  },
  render() {
    return (
      <input
        type="text"
        ref="textInput"
        value={this.data.someVar}
        onInput={this.handleInput} />
    );
  }
});

Components = React.createClass({
  render() {
    return (
      <div>
        <Component_1 />
        <Component_2 />
      </div>
    );
  }
});

Meteor.startup(function() {
  React.render(<Components />, document.body);
});
1 Like

Why would it not be a valid approach. You are using the getMeteorData mixin therefore you could just as have been using a collection to share that data. After all, the getMeteorData is a way to bound a reactive data source to a react component and a session variable is a reactive data source for that matter.

This will work fine and will be performant but there is one issue that may become a problem if your app codebase grows.

Making calls to set the Session in the component itself makes it harder to maintain. Once you have hundreds of these (or even tens) it will be hard to say where an event started, or why one session change triggers another part of the app. I’ve struggled with this firsthand in Blaze apps.

However you can still use a bit of ‘architecture’ from flux to help you. By moving the mutation calls outside of the view, you can control it better and move more of the ‘prep’ logic into this action creator (like the trim here).

It also makes your view easier to test. Debugging is also easier because you can set a breakpoint for one ‘action’ and can log a timeline of actions Example:

Actions = {};

// text - {String} for something
//
Actions.showThing = function(text) {
  text = text.trim();
  console.log("action: showThing", text);
  Session.set('someVar', text);
}
Component_2 = React.createClass({
  handleInput() {
    Actions.showThing(this.refs.textInput.value);
  },
  render() {
    return (
      <input
        type="text"
        ref="textInput"
        value={this.data.someVar}
        onInput={this.handleInput} />
    );
  }
});

If you wanted to be able to log changes before/after you could wrap the Session in a facade so that it internally logs before/after before each set automatically.

5 Likes

You can use AutorunMixin from package https://atmospherejs.com/universe/utilities-react
In autorun you will be read from reactive source of data e.g. session and put whatever you want in react state by (this.setState)

React Meteor Data Mixin is very inefficient and this is a lot of unnecessary hacks for React