javascript 将 React 与 Backbone 一起使用时,我可以避免 forceUpdate() 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21709905/
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
Can I avoid forceUpdate() when using React with Backbone?
提问by Dan Abramov
Facebook Reactencouragesyou to separate mutable (state
) and immutable (props
) state:
Facebook React鼓励您将可变 ( state
) 和不可变 ( props
) 状态分开:
Try to keep as many of your components as possible stateless. By doing this you'll isolate the state to its most logical place and minimize redundancy, making it easier to reason about your application.
尝试让尽可能多的组件保持无状态。通过这样做,您可以将状态隔离到最合乎逻辑的位置并最大限度地减少冗余,从而更容易推理您的应用程序。
When the state changes, you are supposed to call setState
to trigger virtual DOM diff, which will cause a real DOM update only when this is needed.
当状态发生变化时,您应该调用setState
触发虚拟 DOM 差异,这将仅在需要时才会导致真正的 DOM 更新。
There isa way to trigger DOM update manually by calling forceUpdate
but it is discouraged:
有是一种方法来触发DOM更新手动调用forceUpdate
,但它是灰心:
Normally you should try to avoid all uses of
forceUpdate()
and only read fromthis.props
andthis.state
inrender()
. This makes your application much simpler and more efficient.
通常,您应该尽量避免使用
forceUpdate()
并且只从this.props
和this.state
in 中读取render()
。这使您的应用程序更加简单和高效。
However, all React+Backbone examples I have seen ignore this adviceand store models and collections in props
and call forceUpdate
:
然而,我看到的所有 React+Backbone 示例都忽略了这个建议,并将模型和集合存储在props
并调用forceUpdate
:
- http://www.thomasboyt.com/2013/12/17/using-reactjs-as-a-backbone-view.html
- https://github.com/usepropeller/react.backbone/blob/master/react.backbone.js
- https://gist.github.com/ssorallen/7883081
- http://eldar.djafarov.com/2013/11/reactjs-mixing-with-backbone/
- http://www.thomasboyt.com/2013/12/17/using-reactjs-as-a-backbone-view.html
- https://github.com/usepropeller/react.backbone/blob/master/react.backbone.js
- https://gist.github.com/ssorallen/7883081
- http://eldar.djafarov.com/2013/11/reactjs-mixing-with-backbone/
Even React's own example uses forceUpdate
:
甚至 React 自己的例子也使用forceUpdate
:
Is there a better way, though, and what benefits would it give?
但是,有没有更好的方法,它会带来什么好处?
采纳答案by Sophie Alpert
Pete's answer is great.
皮特的回答很棒。
Backbone models are inherently mutative, which (while not a problem in itself) means that when rerendering, you won't have the old version of the model to compare to. This makes it harder to do intelligent optimizations by defining shouldComponentUpdate
methods in key places on your components. (You also lose out on the ability to easily store old versions of your model for other reasons, like implementing undo.)
主干模型本质上是可变的,这(虽然本身不是问题)意味着在重新渲染时,您将无法与旧版本的模型进行比较。这使得通过shouldComponentUpdate
在组件的关键位置定义方法来进行智能优化变得更加困难。(由于其他原因,例如实现 undo,您也无法轻松存储模型的旧版本。)
Calling forceUpdate
merely skips shouldComponentUpdate
and forces the component to rerender. Note that calling render
is usually cheap, and React will still only touch the DOM if the output of render
has changed, so performance problems here aren't common. However, if you have the choice to use immutable data (including passing around raw model property objects from toJSON()
as Pete suggests), I'd highly recommend it.
调用forceUpdate
只是跳过shouldComponentUpdate
并强制组件重新渲染。请注意,调用render
通常很便宜,如果 的输出render
发生变化,React 仍然只会接触 DOM ,因此这里的性能问题并不常见。但是,如果您可以选择使用不可变数据(包括toJSON()
按照 Pete 的建议传递原始模型属性对象),我强烈推荐它。
回答by Dan Abramov
Until there is a better answer, let me quotePete Hunt, a core React developer:
在有更好的答案之前,让我引用核心 React 开发人员Pete Hunt 的话:
The big win with Backbone models was it managed your data flow for you. When you called
set()
it would inform your app that data changed. With React you'll find this to be less necessary because all you need to do is inform the component that owns the state via a callback and React ensures that all children are up-to-date.So this part of backbone is less useful IMO (and people tend to use backbone in this way with React anyway).You don't have to pass pure JSON (though that's what I tend to do and it works well for simple data models), but you will see lots of advantages if you keep your objects immutable.
You can try this out by just calling
toJSON()
on your backbone models and seeing how you like it vs passing the models around.
Backbone 模型的最大优势在于它为您管理数据流。当您调用
set()
它时,它会通知您的应用数据已更改。使用 React,你会发现这不是必要的,因为你需要做的就是通过回调通知拥有状态的组件,React 确保所有子组件都是最新的。所以这部分主干在 IMO 中不太有用(而且人们倾向于以这种方式在 React 中使用主干)。您不必传递纯 JSON(尽管这是我倾向于做的并且它适用于简单的数据模型),但是如果您保持对象不可变,您将看到很多优势。
您可以通过调用
toJSON()
您的主干模型并查看您喜欢它与传递模型来尝试这一点。
(emphasis mine)
(强调我的)
Interestingly, Backbone.React.Componentis the only example I found that uses toJSON
, but for some reason also uses setProps
instead of setState
(which is discouraged too).
有趣的是,Backbone.React.Component是我发现的唯一一个使用 的例子toJSON
,但由于某种原因也使用了setProps
代替setState
(这也是不鼓励的)。
Update
更新
I made a simple mixin based on Pete Hunt's approach (no setProps
, no forceUpdate
):
我根据 Pete Hunt 的方法制作了一个简单的 mixin(不setProps
,不forceUpdate
):
define(function () {
'use strict';
var Backbone = require('backbone'),
_ = require('underscore');
var BackboneStateMixin = {
getInitialState: function () {
return this.getBackboneState(this.props);
},
componentDidMount: function () {
if (!_.isFunction(this.getBackboneState)) {
throw new Error('You must provide getBackboneState(props).');
}
this._bindBackboneEvents(this.props);
},
componentWillReceiveProps: function (newProps) {
this._unbindBackboneEvents();
this._bindBackboneEvents(newProps);
},
componentWillUnmount: function () {
this._unbindBackboneEvents();
},
_updateBackboneState: function () {
var state = this.getBackboneState(this.props);
this.setState(state);
},
_bindBackboneEvents: function (props) {
if (!_.isFunction(this.watchBackboneProps)) {
return;
}
if (this._backboneListener) {
throw new Error('Listener already exists.');
}
if (!props) {
throw new Error('Passed props are empty');
}
var listener = _.extend({}, Backbone.Events),
listenTo = _.partial(listener.listenTo.bind(listener), _, _, this._updateBackboneState);
this.watchBackboneProps(props, listenTo);
this._backboneListener = listener;
},
_unbindBackboneEvents: function () {
if (!_.isFunction(this.watchBackboneProps)) {
return;
}
if (!this._backboneListener) {
throw new Error('Listener does not exist.');
}
this._backboneListener.stopListening();
delete this._backboneListener;
}
};
return BackboneStateMixin;
});
It doesn't care about what kind of models or collections you have.
它不关心你拥有什么样的模型或集合。
The convention is that Backbone models go in props
and their JSON is automatically put by mixin into state
. You need to override getBackboneState(props)
for this to work, and optionally watchBackboneProps
to tell the mixin when to call setState
with fresh values.
约定是Backbone 模型进入props
,它们的 JSON 由 mixin 自动放入state
. 您需要覆盖getBackboneState(props)
它才能工作,并可以选择watchBackboneProps
告诉 mixin 何时setState
使用新值调用。
Usage example:
用法示例:
var InfoWidget = React.createClass({
mixins: [BackboneStateMixin, PopoverMixin],
propTypes: {
stampModel: React.PropTypes.instanceOf(Stamp).isRequired
},
// Override getBackboneState to tell the mixin
// HOW to transform Backbone props into JSON state
getBackboneState: function (props) {
var stampModel = props.stampModel,
primaryZineModel = stampModel.getPrimaryZine();
return {
stamp: stampModel.toJSON(),
toggleIsLiked: stampModel.toggleIsLiked.bind(stampModel),
primaryZine: primaryZineModel && primaryZineModel.toJSON()
};
},
// Optionally override watchBackboneProps to tell the mixin
// WHEN to transform Backbone props into JSON state
watchBackboneProps: function (props, listenTo) {
listenTo(props.stampModel, 'change:unauth_like_count change:is_liked');
listenTo(props.stampModel.get('zines'), 'all');
},
render: function () {
// You can use vanilla JSON values of this.state.stamp,
// this.state.toggleIsLiked and this.state.primaryZine
// or whatever you return from getBackboneState
// without worrying they may point to old values
}
}
Note: mixin requires Underscore 1.6.0+.
注意:mixin 需要 Underscore 1.6.0+。
回答by Magalhas
I'm the developer behind Backbone.React.Component. The reason why we're using setProps is because this is only intended to be called by the component owner (greatest parent). The way I see it, props is better to use for reactive updates (and to pass to child components) than state, but if you can point me some reasons why state is better I'll be happy to start developing towards that change.
我是 Backbone.React.Component 背后的开发者。我们使用 setProps 的原因是因为它仅打算由组件所有者(最大父级)调用。在我看来,props 比 state 更适合用于响应式更新(并传递给子组件),但是如果您能指出一些为什么 state 更好的原因,我将很乐意开始朝着这种变化发展。
For instance sometimes I've got components that delegate to others, where transferPropsTo is pretty handy. Using state kind of makes it harder to achieve that.
例如,有时我有委托给其他人的组件,其中 transferPropsTo 非常方便。使用 state 会使实现这一目标变得更加困难。