javascript 处理 react.js 中的主干模型/集合更改
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20371566/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
handling backbone model/collection changes in react.js
提问by Markus-ipse
I've been working with facebooks framework React.js together with Backbone for the last couple of weeks and I'm still not entirely sure what is the most appropriate way to re-render a React component when there are changes in a Backbone collection that has been passed in as a prop.
在过去的几周里,我一直在使用 facebooks 框架 React.js 和 Backbone,但我仍然不完全确定当 Backbone 集合发生变化时重新渲染 React 组件的最合适方法是什么已作为道具传入。
currently what I do is in componenentWillMount
I set up change/add/remove
listeners on the collection and set state when it triggers:
目前我所做的是在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 <li>{item.get("someAttr")}</li>;
});
return <ul>{listItems}</ul>;
}
I have seen examples where the models are cloned to the state:
我见过将模型克隆到状态的示例:
var updateState = function () {
this.setState({ myCollection: _.clone(this.myCollection.models) });
};
I've also seen variants where model/collection in props is used directly in render instead of using state, and then forceUpdate is called when the collections/model changes, causing the component to re-render
我还看到了在 props 中直接使用模型/集合而不是使用状态的变体,然后在集合/模型更改时调用 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 <li>{item.get("someAttr")}</li>;
});
return <ul>{listItems}</ul>;
}
what benefits and drawbacks are there to the different approaches? Is there a way of doing it that is The React way?
不同的方法有什么优点和缺点?有没有办法做到这一点,那就是React 的方式?
采纳答案by Sophie Alpert
Instead of manually binding event listeners, you can use a mixin based on this BackboneMixin to help automatically bind and unbind the listeners:
您可以使用基于此 BackboneMixin 的 mixin 来帮助自动绑定和取消绑定侦听器,而不是手动绑定事件侦听器:
https://github.com/facebook/react/blob/1be9a9e/examples/todomvc-backbone/js/app.js#L148-L171
https://github.com/facebook/react/blob/1be9a9e/examples/todomvc-backbone/js/app.js#L148-L171
Then you simply write
然后你只需写
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>;
}
});
and the component will be rerendered when anything changes in the collection. You only need to put BackboneMixin on the top-level component -- any descendants will be rerendered automatically at the same time.
当集合中的任何内容发生变化时,组件将被重新渲染。你只需要将 BackboneMixin 放在顶级组件上——任何后代都会同时自动重新渲染。
回答by David Hellsing
IMO, React is still very new and there are very few established rules on how to work with data and reactive models like Backbone. This is also a strength, if you have an existing application - react can be integrated on some smaller parts of it without redefining the entire data flow.
IMO,React 仍然很新,关于如何使用数据和像 Backbone 这样的反应模型的既定规则很少。这也是一个优势,如果你有一个现有的应用程序——react 可以集成到它的一些较小的部分上,而无需重新定义整个数据流。
I believe that since React can call render "smart" at any time – that is only re-rendering parts that have changed – you don't really need to pass data as states. Just pass the data, add listeners on the top component and call forceUpdate
when the model has changed and it will propagate down nicely.
我相信由于 React 可以随时调用“智能”渲染——这只是重新渲染已更改的部分——你真的不需要将数据作为状态传递。只需传递数据,在顶部组件上添加侦听器并forceUpdate
在模型更改时调用,它就会很好地向下传播。
It just seems more "right" to pass backbone models as props, not states.
将主干模型作为道具而不是状态传递似乎更“正确”。
One important thing that I learned the hard way is to use the model.cid
as key (and not Math.random()
) when rendering backbone model lists:
我通过艰难的方式学到的一件重要的事情是在渲染主干模型列表时使用model.cid
as 键(而不是Math.random()
):
var listItems = this.props.myCollection.map(function(item){
return <li key={item.cid}>{item.get("someAttr")}</li>;
});
Because otherwise React won't be able to recognize what model to re-render because all of them will have new keys on each render.
因为否则 React 将无法识别要重新渲染的模型,因为它们在每次渲染时都会有新的键。
回答by duhseekoh
I had been playing around with the BackboneMixin mentioned here and a couple other react resources (of the limited info currently out there). I found that when I was listening to a collection that was being updated from the server, just as many n 'add' events are going to be triggered on the collection and listened to by the BackboneMixin, thus calling force update n number of times, which calls render and whatever is called from render n number of times.
我一直在玩弄这里提到的 BackboneMixin 和其他一些反应资源(目前有限的信息)。我发现当我在监听从服务器更新的集合时,会在集合上触发 n 个“添加”事件并被 BackboneMixin 监听,因此调用 force update n 次,它调用 render 和任何从 render n 调用的内容。
Instead, I used underscore/lo-dash's throttle method to limit the number of times forceUpdate would be called. At the very least this has limited the render method from being called so much. I know react isn't actually doing any DOM manipulation there, and its just a virtual DOM, but still there is no reason it should be called 100 times for 100 immediate additions to a Collection.
相反,我使用下划线/lo-dash 的油门方法来限制调用 forceUpdate 的次数。至少这限制了渲染方法被调用这么多。我知道 react 实际上并没有在那里进行任何 DOM 操作,它只是一个虚拟 DOM,但仍然没有理由为 100 次立即添加到集合中而应调用 100 次。
So my solution looks like https://gist.github.com/ssorallen/7883081but with the componentDidMount method like this instead:
所以我的解决方案看起来像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);
}
回答by user2779653
react.backboneseems to be the most recent solution for React-Backbone integration. Haven't tested it yet though.
react.backbone似乎是 React-Backbone 集成的最新解决方案。不过还没有测试过。
回答by jbaiter
There's another BackboneMixin, courtesy of Eldar Djafarov, that re-renders your component when the model changes and also provides a very convenient way to get two-way databinding:
Eldar Djafarov 提供了另一个 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)
};
}
}
Here's his jsFiddle that demonstrates the usage: http://jsfiddle.net/djkojb/qZf48/13/
这是他的 jsFiddle 演示用法:http: //jsfiddle.net/djkojb/qZf48/13/