Подтвердить что ты не робот

Обработка базовой модели/изменения коллекции в response.js

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

в настоящее время то, что я делаю, находится в componentenentWillMount. Я настроил изменение/добавление/удаление слушателей в коллекции и установил состояние, когда он вызывает:

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 <li>{item.get("someAttr")}</li>;
    });
    return <ul>{listItems}</ul>;
}

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

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

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

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 <li>{item.get("someAttr")}</li>;
    });
    return <ul>{listItems}</ul>;
}

Какие преимущества и недостатки существуют для разных подходов? Есть ли способ сделать это, то есть "The React way"?

4b9b3361

Ответ 1

Вместо ручного связывания прослушивателей событий вы можете использовать mixin на основе этого 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 <li>{item.get("someAttr")}</li>;
        });
        return <ul>{listItems}</ul>;
    }
});

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

Ответ 2

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

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

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

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

var listItems = this.props.myCollection.map(function(item){
    return <li key={item.cid}>{item.get("someAttr")}</li>;
});

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

Ответ 3

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

Вместо этого я использовал метод underscore/lo-dash throttle, чтобы ограничить количество раз, которое будет вызвано forceUpdate. По крайней мере, это ограничило метод визуализации так называемым. Я знаю, что реакция на самом деле не делает никаких манипуляций с 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);
}

Ответ 4

Там еще есть 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)
      };
    }
  }

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

Ответ 5

react.backbone, по-видимому, является самым последним решением для интеграции React-Backbone. Еще не протестировали его.