React.js. Стоит ли делать главный компонент «глобальным»?

Пробую react.js, пока все нравится, но возник вопрос по проектированию архитектуры.

Допустим, есть приложение со вложенными компонентами.
App > ItemsList > Item > ActiveElement
Где, App - главный компонент (стрелочкам указан уровень вложенности), ActiveElement - крайний дочерний элемент, предполагающий взаимодействие с пользователем.

Вся логика находится в App, дочерние компоненты формируются на основе переданных props. Вроде как классическая схема, но, мне не очень нравится проксировать функции через всю цепочку потомков от App до ActiveElement, если последний, к примеру, при клике, должен изменить в App какой-то state.

То есть, выглядит это примерно так:
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>
	}
});


Здесь, мы проксируем функцию onToggleOption для кнопки, через всех ее родителей. Если таких кнопок и/или родителей будет много, подобное занятие может вызвать неслабый дискомфорт.

Первое, что приходит на ум, сделать ссылку на родительский класс App и обращаться в дочерних элементах к нужным функциям непосредственно через нее.
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>
	}
});


Собственно, интересует, есть ли какие-то очевидные или не очевидные минусы такого подхода. Или может быть есть более правильный подход, как упростить связывание компонентов?
  • Вопрос задан
  • 5204 просмотра
Решения вопроса 1
icelaba
@icelaba
Знаю и умею всё
props можно прокидывать пользуясь jsx синтаксисом (раньше это был метод transferPropsTo)
сейчас так см. https://gist.github.com/sebmarkbage/a6e220b7097eb3...

тогда не придется бесконечно дублировать имя колбека.

Вообще рекомендую писать используя flux facebook.github.io/flux методологию, тогда изменения state будут идти через отдельные компоненты и такого наследования пропсов удается избежать.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Laiff
@Laiff
Front-end developer
Существует еще одна возможность прокидывания callback'ов это
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>
  }
});


Пример конечно утрированный получился, но основная суть такая:
- Корневой элемент конмпонента объявляет контекст, которым пользуются все его потомки в обязательном порядке

В своей разработке у меня применяется архитекткра Reflux, поэтому в контексте прокидываются события, получается достаточно удобно, пример:
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>
  }
});
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы