Как перейти от jQuery к React.js?

Я читаю React в течение нескольких дней. Я могу понять большую часть того, что я смотрю, но я не совсем уверен в своей способности писать. Я работал над небольшим веб-приложением, которое делает все его генерации html через jQuery и добавляя элементы друг к другу. Я хотел бы попытаться восстановить его с помощью React, потому что считаю, что это будет быстрее. Этот JSFiddle является небольшим примером того, над чем я работаю. Как вы могли бы написать его с помощью React?

JS:

function remove() {
    this.remove();
}

function timed_append_new_element() {
    setTimeout(function () {
        var added_content = $("<span />", {
            class: "added_content",
            text: "Click to close",
            click: remove
        });
        container.append(added_content);
    }, 3000);
}

function append_new_element() {
    var added_content = $("<span />", {
        class: "timed_added_content",
        text: "Click to close",
        click: remove
    });
    container.append(added_content);
}


var container = $("<div />", {
    class: "container"
});
var header = $("<span />", {
    class: "header",
    text: "jQuery to React.js Header"
});
var add_button = $("<button />", {
    class: "add_button",
    text: "Add Element",
    click: append_new_element
});
var timed_add_button = $("<button />", {
    class: "add_button",
    text: "Add Element in 3 seconds",
    click: timed_append_new_element
});
container.append(header);
container.append(add_button);
container.append(timed_add_button);
$("body").append(container);

Ответ 1

Есть несколько основных принципов, которые следует учитывать, что может помочь вам создать хорошее приложение React:

Ваш пользовательский интерфейс должен быть функцией данных

Во многих приложениях стиля "jQuery soup" бизнес-логика для приложения, данных приложения и кода взаимодействия с пользовательским интерфейсом смешиваются. Это затрудняет отладку этих видов приложений и, в особенности, трудно подрастает. Реагируйте, как и многие современные клиентские платформы приложений, внедряйте идею о том, что пользовательский интерфейс представляет собой просто представление ваших данных. Если вы хотите, чтобы ваш пользовательский интерфейс изменился, вы должны изменить часть данных и разрешить любую систему привязки, используемую инфраструктурой для обновления пользовательского интерфейса.

В React каждый компонент (в идеале) представляет собой функцию из двух частей данных - свойств, переданных экземпляру компонента, и состояния, которое компонент управляет внутренне. Учитывая те же свойства (или "реквизит" ) и состояние, компонент должен отображать таким же образом.

Это может быть немного абстрактная идея без конкретных примеров, поэтому имейте это в виду, пока мы продвигаемся дальше.

Не касайтесь DOM

В React, даже больше, чем другие связанные с данными фреймворки, вы должны стараться не манипулировать DOM напрямую, если это вообще возможно. Многие характеристики производительности и сложности React возможны только потому, что React использует виртуальную DOM с различными алгоритмами для работы на реальном DOM. Каждый раз, когда вы создаете компонент, который тянется и выполняет свои собственные манипуляции с DOM, вы должны спросить себя, можете ли вы создать такую ​​же функцию более идиоматично с помощью возможностей React virtual DOM.

Конечно, иногда вам нужно получить доступ к DOM, или вы захотите включить какой-либо плагин jQuery, не перестраивая его в React. В такие моменты React дает вам хорошие крючки жизненного цикла компонентов, которые вы можете использовать для обеспечения того, чтобы производительность React не слишком сильно страдала (или, в некоторых случаях, чтобы сохранить ваш компонент от простого взлома).

Не манипулирование DOM идет рука об руку с "UI как функцией данных" выше.

Инвертировать поток данных

В большом приложении React может быть сложно отслеживать, какой подкомпонент управляет определенной частью данных приложения. По этой причине команда React рекомендует хранить логику манипулирования данными в центральном месте. Самый простой способ сделать это - передать обратные вызовы в дочерние компоненты; существует также архитектура, разработанная в Facebook под названием Flux, которая имеет собственный сайт.

Создание составных компонентов

Много раз, может возникнуть соблазн написать большой компонент, который управляет несколькими частями состояния или несколькими частями логики пользовательского интерфейса. Там, где это возможно (и в пределах разумного), вы должны рассмотреть возможность разбиения более крупных компонентов на более мелкие, которые работают с одной частью данных или логикой пользовательского интерфейса. Это значительно упрощает расширение и перемещение фрагментов вашего приложения.

Остерегайтесь изменяемых данных

Так как состояние компонента должно обновляться только через вызовы this.setState внутри компонента, полезно быть осторожным с изменяемыми данными. Это вдвойне верно, когда несколько функций (или компонентов!) Могут обновлять изменяемый объект в том же тике; Реакция может попытаться внести изменения в состояние штата, и вы можете потерять обновления! Как упоминалось в комментариях Eliseu Monar, рассмотрите клонирование изменяемых объектов перед их мутированием. React имеет помощников по неизменности, которые могут помочь.

Другой вариант - отказаться от сохранения изменяемых структур данных непосредственно в состоянии вообще; описанная выше картина потока, представляет интерес для этой идеи.


Там есть отличная статья на сайте React под названием Thinking in React, в котором рассказывается, как вы можете взять идею или макет и превратить ее в приложение React, и Я настоятельно рекомендую это преодолеть. В качестве конкретного примера давайте взглянем на предоставленный вами код. У вас по существу есть один элемент данных для управления: список содержимого, который существует внутри элемента container. Все изменения в пользовательском интерфейсе могут быть представлены дополнениями, удалениями и изменениями этих данных.

Применяя вышеприведенные принципы, ваше окончательное приложение может выглядеть примерно так:

/** @jsx React.DOM */

var Application = React.createClass({
  getInitialState: function() {
    return {
      content: []
    };
  },

  render: function() {
    return (
      <div className="container">
        <span className="header">jQuery to React.js Header</span>
        <button className="add_button"
                onClick={this.addContent}>Add Element</button>
        <button className="add_button"
                onClick={this.timedAddContent}>Add Element in 3 Seconds</button>
        {this.state.content.map(function(content) {
          return <ContentItem content={content} removeItem={this.removeItem} />;
        }.bind(this))}
      </div>
    );
  },

  addContent: function() {
    var newItem = {className: "added_content", text: "Click to close"},
        content = this.state.content,
        newContent = React.addons.update(content, {$push: [newItem]});
    this.setState({content: newContent});
  },

  timedAddContent: function() {
    setTimeout(function() {
      var newItem = {className: "timed_added_content", text: "Click to close"},
          content = this.state.content,
          newContent = React.addons.update(content, {$push: [newItem]});
      this.setState({content: newContent});
    }.bind(this), 3000);
  },

  removeItem: function(item) {
    var content = this.state.content,
        index = content.indexOf(item);
    if (index > -1) {
      var newContent = React.addons.update(content, {$splice: [[index, 1]]});
      this.setState({content: newContent});
    }
  }
});

var ContentItem = React.createClass({
  propTypes: {
    content: React.PropTypes.object.isRequired,
    removeItem: React.PropTypes.func.isRequired
  },

  render: function() {
    return <span className={this.props.content.className}
                 onClick={this.onRemove}>{this.props.content.text}</span>;
  },

  onRemove: function() {
    this.props.removeItem(this.props.content);
  }
});

React.renderComponent(<Application />, document.body);

Вы можете увидеть код в действии в этом JSFiddle: http://jsfiddle.net/BinaryMuse/D59yP/

Приложение состоит из двух компонентов: компонент верхнего уровня под названием Application, который управляет (в своем состоянии) массивом с именем content и компонентом с именем ContentItem, который представляет собой пользовательский интерфейс и поведение один элемент из этого массива. Application render возвращает элемент ContentItem для каждого элемента массива содержимого.

Следует заметить, что вся логика управления значениями внутри массива content обрабатывается в компоненте Application; компонентам ContentItem передается ссылка на метод Application removeItem, который делегат ContentItem делегирует при нажатии. Это сохраняет всю логику управления состоянием внутри компонента верхнего уровня.