F
F
Freew1nd2014-12-12 00:17:33
React
Freew1nd, 2014-12-12 00:17:33

React.js Should you make the main component "global"?

I'm trying react.js, so far I like everything, but a question arose about architecture design.
Let's say we have an application with nested components.
App > ItemsList > Item > ActiveElement
Where, App is the main component (the nesting level is indicated by the arrows), ActiveElement is the last child element, which assumes user interaction.
All logic is in the App, child components are formed based on the passed props. It seems like a classic scheme, but I don’t really like proxying functions through the entire chain of descendants from App to ActiveElement, if the latter, for example, when clicked, should change some state in App.
That is, it looks something like this:

var App = React.createClass({
  getInitialState: function(){
    return {
      option: false
    };
  },

  onToggleOption: function(){
    var option = this.state.option;

    option = !option;

    this.setState({option: option});
  },

  render: function(){
    return <ItemsList onToggleOption={this.onToggleOption} />
  }
});

var ItemsList = React.createClass({
  render: function(){
    return <Item onToggleOption={this.props.onToggleOption} />
  }
});

var Item = React.createClass({
  render: function(){
    return <ActiveElement onToggleOption={this.props.onToggleOption} />
  }
});

var ActiveElement = React.createClass({
  render: function(){
    return <button onClick={this.props.onToggleOption}>Click me</button>
  }
});

Here, we're proxying the button's onToggleOption function through all of its parents. If there are many such buttons and / or parents, such an activity can cause considerable discomfort.
The first thing that comes to mind is to make a reference to the parent App class and access the necessary functions in the child elements directly through it.
var AppLink = null;

var App = React.createClass({
  getInitialState: function(){
    return {
      option: false
    };
  },

  componentDidMount: function(){
    AppLink = this;
  },

  //...
});

//...

var ActiveElement = React.createClass({
  render: function(){
    return <button onClick={AppLink.onToggleOption}>Click me</button>
  }
});

Actually, I'm interested in whether there are any obvious or not obvious disadvantages of this approach. Or maybe there is a more correct approach, how to simplify the binding of components?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
I
Ivan Starkov, 2014-12-12
@Freew1nd

props can be passed using jsx syntax (it used to be the transferPropsTo method)
now see https://gist.github.com/sebmarkbage/a6e220b7097eb3...
then you don't have to endlessly duplicate the callback name.
In general, I recommend writing using the flux facebook.github.io/flux methodology, then state changes will go through separate components and such inheritance of props can be avoided.

A
Andrey Antropov, 2015-01-29
@Laiff

There is one more possibility of passing callbacks:

var App = React.createClass({
  ...
  render: function() {
    return <ItemsList context={{onToggleOption: this.onToggleOption}} />
  }
});

var ActiveElement = React.createClass({
  childContextTypes: {
    onToggleOption: React.PropTypes.func.isRequired
  },

  render: function(){
    return <button onClick={this.context.onToggleOption}>Click me</button>
  }
});

The example turned out to be exaggerated, of course, but the main essence is this:
- The root element of the component declares the context that all its descendants use without fail.
In my development, I use the Reflux architecture, so events are thrown in the context, it turns out quite conveniently, example:
var ListActions = Reflux.createActions('toggleOption');

var App = React.createClass({
  ...
  render: function() {
    return <ItemsList context={{listActions: ListActions}} />
  }
});

var ActiveElement = React.createClass({
  childContextTypes: {
    listActions: React.PropTypes.objectOf(React.PropTypes.func).isRequired
  },

  render: function(){
    return <button onClick={this.context.listActions.toggleOption}>Click me</button>
  }
});

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question