在有更好的答案之前,让我引用 核心 React 开发人员Pete Hunt 的话:
Backbone 模型的最大优势在于它为您管理数据流。当您调用set()
它时,它会通知您的应用数据已更改。使用 React,你会发现这不是必要的,因为你需要做的就是通过回调通知拥有状态的组件,React 确保所有子组件都是最新的。所以这部分主干在 IMO 中不太有用(而且人们倾向于以这种方式在 React 中使用主干)。
您不必传递纯 JSON(尽管这是我倾向于做的并且它适用于简单的数据模型),但是如果您保持对象不可变,您将看到很多优势。
您可以通过调用toJSON()
您的主干模型并查看您喜欢它与传递模型来尝试这一点。
(强调我的)
有趣的是,Backbone.React.Component是我发现的唯一一个使用 的例子toJSON
,但由于某种原因也使用了setProps
代替setState
(这也是不鼓励的)。
更新
我根据 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;
});
它不关心你拥有什么样的模型或集合。
约定是Backbone 模型进入props
,它们的 JSON 由 mixin 自动放入state
. 您需要覆盖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 需要 Underscore 1.6.0+。