Вопрос по backbone.js, reactjs, javascript – обработка изменений в модели / коллекции магистрали вact.js

31

последние пару недель я работаю с фреймворком Facebook React.js вместе с Backbone, и яЯ до сих пор не совсем уверен, что является наиболее подходящим способом повторного рендеринга компонента React, когда есть изменения в коллекции Backbone, которая была передана как опора.

в настоящее время то, что я делаю, находится вcomponenentWillMount Я настроилchange/add/remove слушатели на коллекции и устанавливают состояние, когда это вызывает:

componentWillMount: function(){
    var myCollection = this.props.myCollection;
    var updateState = function(){
        this.setState({myCollection: myCollection.models});
    }

    myCollections.on("add remove", updateState, this);
    updateState();
}

render: function(){
    var listItems = this.state.myCollection.map(function(item){
        return {item.get("someAttr")};
    });
    return {listItems};
}

Я видел примеры, когда модели клонируются в состояние:

var updateState = function () {
    this.setState({ myCollection: _.clone(this.myCollection.models) });
};

Мы также видели варианты, в которых модель / коллекция в подпорках используется непосредственно при рендеринге вместо использования состояния, а затем вызывается forceUpdate при изменении коллекций / модели, что вызывает повторный рендеринг компонента

componentWillMount: function(){
    var myCollection = this.props.myCollection;
    myCollections.on("add remove", this.forceUpdate, this);
}

render: function(){
    var listItems = this.props.myCollection.map(function(item){
        return {item.get("someAttr")};
    });
    return {listItems};
}

какие преимущества и недостатки есть у разных подходов? Есть ли способ сделать это,Реактивный путь?

Ваш Ответ

5   ответов
1

react.backbone похоже, самое последнее решение для интеграции React-Backbone. Haven»Я еще не проверил это.

5

Я играл с BackboneMixin, упомянутым здесь, и парой других ресурсов реагирования (из ограниченной информации, доступной в настоящее время). Я обнаружил, что когда я слушал коллекцию, которая обновлялась с сервера, столько жедобавлять' события будут инициироваться в коллекции и прослушиваться BackboneMixin, таким образом вызывая принудительное обновление n раз, что вызывает render и все, что вызывается из render, n раз.

Вместо этого я использовал подчеркивание / lo-dash 's throttle метод для ограничения количества вызовов forceUpdate. По крайней мере, это ограничило вызов метода render. Я знаю, реагировать неНа самом деле там не делается никаких манипуляций с DOM, это просто виртуальный DOM, но все же нет никаких причин, по которым его следует вызывать 100 раз для 100 немедленных добавлений в коллекцию.

Так что мое решение выглядит такhttps://gist.github.com/ssorallen/7883081 но вместо этого с помощью метода componentDidMount:

componentDidMount: function() {
  //forceUpdate will be called at most once every second
  this._boundForceUpdate = _.throttle(this.forceUpdate.bind(this, null), 1000);
  this.getBackboneObject().on("all", this._boundForceUpdate, this);
}
Это тот, кого ям в настоящее время использую. Это'не совсем понятно, как ябуду обрабатывать события с большей детализацией. Но я полагаю, что могу положитьсяlistenTo и так далееgetInitialState... tutuca
1

Там'другой BackboneMixin,любезно предоставлено Эльдаром Джафаровым, который повторно отображает ваш компонент при изменении модели, а также предоставляет очень удобный способ получить двустороннюю привязку данных:

  var BackboneMixin = {
    /* Forces an update when the underlying Backbone model instance has
     * changed. Users will have to implement getBackboneModels().
     * Also requires that React is loaded with addons.
     */
    __syncedModels: [],
    componentDidMount: function() {
      // Whenever there may be a change in the Backbone data, trigger a reconcile.
      this.getBackboneModels().forEach(this.injectModel, this);
    },
    componentWillUnmount: function() {
      // Ensure that we clean up any dangling references when the component is
      // destroyed.
      this.__syncedModels.forEach(function(model) {
        model.off(null, model.__updater, this);
      }, this);
    },
    injectModel: function(model){
      if(!~this.__syncedModels.indexOf(model)){
        var updater = this.forceUpdate.bind(this, null);
        model.__updater = updater;
        model.on('add change remove', updater, this);
      }
    },
    bindTo: function(model, key){
      /* Allows for two-way databinding for Backbone models.
       * Use by passing it as a 'valueLink' property, e.g.:
       *   valueLink={this.bindTo(model, attribute)} */
      return {
        value: model.get(key),
        requestChange: function(value){
            model.set(key, value);
        }.bind(this)
      };
    }
  }

Вот's его jsFiddle, который демонстрирует использование:http://jsfiddle.net/djkojb/qZf48/13/

Может кто-нибудь объяснить, как модель добавляется в __syncedModels? Или есть ошибка, и это нет? Tom
@Tom проверьте скрипку, в вашем пользовательском компоненте вы должны определить getBackboneModels, который будет возвращать модели, которые войдут в __syncedModels Eldar Djafarov
Я понимаю, что должно произойти, я просто могуСледуйте, как возвращаемое значение изgetBackboneModels добавляется в__syncedModels в миксине: должно быть пропущена строка -this.__syncedModels.push(model); право? Tom
То есть Скрипка работает, как и другие простые применения, но__syncedModels охранник на самом деле не работает, так что еслиgetBackboneModels возвращали один и тот же экземпляр модели более одного раза,forceUpdate будет уволен несколько раз. Tom
10

ИМО, React все еще очень нова, и очень мало установленных правил работы с данными и реактивными моделями, такими как Backbone. Это также является преимуществом, если у вас есть существующее приложение - реакция может быть интегрирована в некоторые его меньшие части без переопределения всего потока данных.

Я считаю, что так как React может вызывать рендер "умный" в любое время - это только рендеринг частей, которые изменились - ты недействительно нужно передавать данные как состояния. Просто передайте данные, добавьте слушателей на верхний компонент и вызовитеforceUpdate когда модель изменилась, и она будет хорошо распространяться вниз.

Просто кажется большеправо" передавать магистральные модели как реквизиты, а не штаты.

Одна важная вещь, которую я выучил трудным путем, - это использоватьmodel.cid в качестве ключа (а неMath.random()) при рендеринге списков моделей магистралей:

var listItems = this.props.myCollection.map(function(item){
    return {item.get("someAttr")};
});

Потому что иначе React победилне сможет распознать, какую модель рендерить, потому что у каждого из них будут новые ключи при каждом рендеринге.

Мне нравится, что этот способ немного более лаконичен, чем добавление коллекции в состояние, но с другой стороны этоНемного яснее, если что-то, что меняется (например, коллекция), находится внутри состояния, так как оно 'СОСТОЯНИЕ коллекции, которая вас интересует, когда вы визуализируете. Я'Я все еще немного разорван относительно того, какой путь предпочтительнее. Markus-ipse
12

Вместо того, чтобы вручную связывать прослушиватели событий, вы можете использовать миксин, основанный на этом BackboneMixin, чтобы помочь автоматически связывать и отменять привязку слушателей:

https://github.com/facebook/react/blob/1be9a9e/examples/todomvc-backbone/js/app.js#L148-L171

Тогда ты просто пишешь

var List = React.createClass({
    mixins: [BackboneMixin],

    getBackboneModels: function() {
        return [this.props.myCollection];
    },

    render: function(){
        var listItems = this.props.myCollection.map(function(item){
            return {item.get("someAttr")};
        });
        return {listItems};
    }
});

и компонент будет перерисован, когда что-либо изменится в коллекции. Вам нужно только поместить BackboneMixin в компонент верхнего уровня - все потомки будут автоматически перерисованы одновременно.

Полный пример BackboneMixin:gist.github.com/ssorallen/7883081 Ross Allen
Re: положить его только в компонент верхнего уровня, если в дочернем компоненте мне нужно нарезать коллекцию или создать другое подмножество чего-то из этого, я прав, если предположить, что подмножество / нарезанный набор потребует еще одного экземпляра mixin ? Благодарю. amankapur91
Обратите внимание, что в связанной реализации BackboneMixin getBackboneModels всегда должна возвращать один и тот же список моделей. Если getBackboneModels изменится, чтобы вернуть разные объекты, обработчики событий победятбыть должным образом связаны и не связаны. Если это проблема для васНетрудно сделать BackboneMixin немного умнее. Sophie Alpert
Поскольку события Backbone Model передаются в содержащую Коллекцию, Mixin следует немного изменить для прослушивания Коллекции. Я закончил с:componentDidMount: function() { this._boundForceUpdate = this.forceUpdate.bind(this, null); this.getBackboneObject().on("all", this._boundForceUpdate, this); }, Ross Allen

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