Обработка базовой модели/изменения коллекции в 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"?
Ответы
Ответ 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. Еще не протестировали его.