mannaro
@mannaro
Умею профессионально гуглить

Как правильно разбивать код на компоненты?

День добрый! Начал я активно изучать React и столкнулся с очень интересным вопросом: а как же именно делить код на компоненты? Сразу скажу, компонентный подход мне очень понравился, однако, отойти от MVC достаточно тяжело, посему и задаю этот вопрос здесь.

Например, у меня есть страница, отображающая результаты конкурса. Ее функция render слишком жирная (на мой взгляд) и ее хотелось бы разбить на более мелкие части. Однако, я не очень представляю как сделать это. Имею ввиду, разделить так, чтобы в этом был смысл. Так-то можно и просто разбить ее на 3-4 части, затем склеив воедино. Однако, в таком случае у меня не будет использоваться вся мощь компонентов - реюзабельность.

Пример страницы:
spoiler
var formResults = React.createClass({
  mixins: [ReactMeteorData],

  getMeteorData() {
    return {
      stats: FormStats.find({ form: this.props._id }).fetch(),
      percent: (FormStats.find({ form: this.props._id }).count() / this.props.viewed).toFixed(2) * 100,
      ended: FormStats.find({ form: this.props._id }).count(),
      average: this.average(),
      charts: Forms.findOne(this.props._id).items.filter(item => {
        var items = ['checkbox', 'dropdown', 'rating'];
        return items.indexOf(item.type) > -1;
      })
    };
  },
  getInitialState() {
    return {
      page: 0
    };
  },

  t() {
    return App.lang.t(...arguments);
  },
  average() {
    var res = [];

    FormStats.find({ form: this.props._id }).map(function(stat) {
      res.push(stat.createdAt - stat.from);
    });

    var dur = moment.duration(lodash.sum(res) / res.length);

    return [dur.minutes(), dur.seconds()].map(i => i < 10 ? '0' + i : i).join(':');
  },
  date(item) {
    return moment(item.createdAt).format('L')
  },
  getPageClass(id) {
    var str = 'info panel panel-default';
    if(this.state.page != id) str += ' hidden';

    return str;
  },
  setPage(id) {
    return (e) => {
      this.setState({ page: id });
    };
  },
  isActive(id) {
    return this.state.page == id && 'active';
  },
  chartConfig(chart) {
    console.log(chart);

    return {};
  },
  render() {
    return <div id="form" className="container">
      <Steps />
      <div id="questions" className="stat">
        <h3>
          {this.props.name}
        </h3>
        <div className="row">
          <div className="col-xs-6">
            <Progress percent={this.data.percent} />
          </div>
        </div>
        <div className="row">
          <div className="col-xs-3">
            <Statistic
              title={this.props.viewed}
              message={this.t('polls.stat.started')} />
          </div>
          <div className="col-xs-3">
            <Statistic
              title={this.data.ended}
              message={this.t('polls.stat.ended')} />
          </div>
          <div className="col-xs-3">
            <Statistic
              title={this.data.average}
              message={this.t('polls.stat.average')} />
          </div>
          <div className="col-xs-3">
            <Statistic
              title={0}
              message={this.t('polls.stat.clicked')} />
          </div>
        </div>
        <div className="row">
          <div className="col-xs-12">
            <ul className="nav nav-tabs nav-justified panelled">
              <li
                className={this.isActive(0)}
                onClick={this.setPage(0)}>
                <a href="#results">Результаты</a>
              </li>
              <li
                className={this.isActive(1)}
                onClick={this.setPage(1)}>
                <a href="#stat">Статистика</a>
              </li>
            </ul>
            <div className={this.getPageClass(0)}>
              <div className="panel-content">
                {this.data.stats.map(item => {
                  var path = Router.path('form/result', { _id: this.props._id, result: item._id });

                  return <div className="row" key={item._id}>
                    <div className="col-xs-4">
                      {item.ip}
                    </div>
                    <div className="col-xs-4">
                      {this.date(item)}
                    </div>
                    <div className="col-xs-4">
                      <a href={path}>Результаты</a>
                    </div>
                  </div>;
                })}
              </div>
            </div>
            <div className={this.getPageClass(1)}>
              {this.data.charts.map(chart => {
                return <Highcharts key={chart._id} config={this.chartConfig(chart)} />;
              })}
            </div>
          </div>
        </div>
      </div>
    </div>;
  }
});
  • Вопрос задан
  • 1840 просмотров
Решения вопроса 2
Laiff
@Laiff
Front-end developer
Для того чтобы был смысл в получаемых компонентах, можно пойти например от дизайна, то есть взять и просто разделить дизайн страницы на логические блоки, это будут самые крупные контейнеры, затем в них начать выделять логически отделенные или повторяющиеся элементы.
Данный процесс можно повторять очень долго, но важно остановится в момент когда это уже не несет логической основы.
Также рекомендую посмотреть на подход атомарного дизайна,
Это статью с точки зрения дизайна sketchapp.me/verstka-sajta-s-pomoshhyu-sketch-i-at...
Это со стороны организации bradfrost.com/blog/post/atomic-web-design
Не привязано к реакту, но хорошо ложится на него.
Ответ написан
Комментировать
Не стесняйтесь делать глупые (dumb) компоненты. Негласное правило - метод рендер должен помещаться на одном экране. Сделайте отдельный компонент со статистикой, с результатами (или что там у Вас еще).

Компонент для вывода статистики так и просится:

<MyStatistic items={[ { titile: 'abc', message:  'cde' } ]}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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