Javascript 使用React with主干时是否可以避免forceUpdate()?
您可以将可变(Javascript 使用React with主干时是否可以避免forceUpdate()?,javascript,backbone.js,reactjs,Javascript,Backbone.js,Reactjs,您可以将可变(状态)和不可变(道具)状态分开: 尽量保持尽可能多的组件无状态。通过这样做,您可以将状态隔离到最符合逻辑的位置,并最大限度地减少冗余,从而更容易对应用程序进行推理 当状态发生变化时,您应该调用以触发虚拟DOM diff,这将仅在需要时才导致真正的DOM更新 有一种方法可以通过调用手动触发DOM更新,但它是: 通常您应该尽量避免使用forceUpdate(),只从渲染()中的this.props和this.state中读取。这使您的应用程序更加简单和高效 但是,我看到的所有React
状态
)和不可变(道具
)状态分开:
尽量保持尽可能多的组件无状态。通过这样做,您可以将状态隔离到最符合逻辑的位置,并最大限度地减少冗余,从而更容易对应用程序进行推理
当状态发生变化时,您应该调用以触发虚拟DOM diff,这将仅在需要时才导致真正的DOM更新
有一种方法可以通过调用手动触发DOM更新,但它是:
通常您应该尽量避免使用forceUpdate()
,只从渲染()中的this.props和this.state中读取。这使您的应用程序更加简单和高效
但是,我看到的所有React+主干示例都忽略了这个建议,将模型和集合存储在道具中,并调用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;
});
甚至React自己的示例也使用了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;
});
但是,有更好的方法吗?它会带来什么好处?在有更好的答案之前,让我作为一名核心开发者:
主干机型的最大优势在于它可以为您管理数据流。当您调用set()
时,它会通知您的应用程序数据已更改使用React时,您会发现这一点不太必要,因为您所需要做的只是通过回调通知拥有状态的组件,React确保所有子项都是最新的。因此主干的这一部分在IMO中不太有用(而且人们总是以这种方式在React中使用主干)
您不必传递纯JSON(尽管我倾向于传递纯JSON,并且它对简单数据模型很有效),但是如果您保持对象不变,您将看到很多优势
您可以通过在主干模型上调用toJSON()
来尝试这一点,并查看您对它的喜欢程度,而不是将模型传递出去。
(强调矿山)
有趣的是,这是我发现的唯一一个使用toJSON
的示例,但出于某种原因,它也使用setProps
而不是setState
(即)
更新
我根据皮特·亨特的方法做了一个简单的混音(nosetProps
,noforceUpdate
):
它不关心你有什么样的型号或系列
约定是主干模型进入道具
,它们的JSON通过mixin自动进入状态
。您需要覆盖getBackboneState(props)
以使其正常工作,还可以选择watchBackboneProps
告知mixin何时使用新值调用setState
用法示例:
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
}
}
注意:mixin需要下划线1.6.0+。Pete的答案很好
主干模型本质上是变异的,这(虽然本身不是问题)意味着在重新招标时,您将无法与旧版本的模型进行比较。这使得通过在组件的关键位置定义方法来进行智能优化变得更加困难。(由于其他原因,您也无法轻松存储模型的旧版本,例如。)
调用forceUpdate
只会跳过shouldComponentUpdate
并强制组件重新加载。请注意,调用render
通常成本较低,如果render
的输出发生了更改,React仍将只触及DOM,因此这里的性能问题并不常见。但是,如果您可以选择使用不可变数据(包括按照Pete的建议将原始模型属性对象从传递到json()
),我强烈推荐它。我是Backbone.React.Component的开发人员。我们之所以使用setProps,是因为它只打算由组件所有者(最大的父级)调用。在我看来,道具比状态更好地用于反应式更新(并传递给子组件),但如果你能告诉我一些为什么状态更好的原因,我将很高兴开始朝着这一变化发展
例如,有时我会将组件委托给其他组件,而transferPropsTo非常方便。使用状态会使实现这一目标变得更加困难。非常感谢!我已经找到了,但是它使用了setProps
和toJSON
。根据我的理解,我可以使用他们的方法,但可以使用setState
来代替。没错,也可以使用
或类似方法来代替传递
。(据我所知,Backbone.React.Component失去了组件的易组合性,这是React的主要功能之一。不过,为组件使用模型道具很有趣。)如果您绑定到主干模型上的change
事件,您应该可以访问和。因此,您应该能够实现“智能优化”。@EdwardsMith这是真的,但是如果您将模型存储在道具上,那么我认为这实际上对您没有帮助,因为您无法轻松访问shouldComponentUpdate
中的新旧属性。(在某些情况下,React会将多个渲染批处理为一个渲染,因此主干的previousAttributes()
将是错误的。)@BenAlpert-True,您不能使用shouldComponentUpdate,但是您可以在主干网中执行基本相同的操作。模型更改处理程序-决定是否需要更新,如果需要,则调用forceUpdate。虽然不是最好的味道,但我对自己的看法是,对内部组件状态使用state
,它不与任何人共享,但对主干模型不使用。对于主干模型和集合,我将toJSON
结果作为props
传递。当主干模型更改时,我再次调用renderComponent
,并重新创建整个组件层次结构