Facebook React奨励 可変(state
)状態と不変(props
)状態を分離する:
できるだけ多くのコンポーネントをステートレスにしてください。これにより、状態を最も論理的な場所に分離し、冗長性を最小限に抑えて、アプリケーションの推論を容易にします。
状態が変化すると、 setState
を呼び出して仮想DOM diffをトリガーします。これにより、必要な場合にのみ実際のDOM更新が行われます。
そこにがあります forceUpdate
を呼び出すことでDOM更新を手動でトリガーする方法ですが、 discouraged :
通常
forceUpdate()
のすべての使用を避け、_this.props
_および_this.state
_からのみ読み取るようにしてくださいrender()
。これにより、アプリケーションが非常にシンプルかつ効率的になります。
ただし、私が見たすべてのReact + Backboneの例はこのアドバイスを無視し、モデルとコレクションをprops
に保存し、forceUpdate
を呼び出します。
React自身の例でもforceUpdate
を使用しています:
しかし、より良い方法はありますか、それはどのような利益をもたらしますか?
ピートの答えは素晴らしい。
バックボーンモデルは本質的に変異型であり、(それ自体は問題ではありませんが)再レンダリングするときに、比較するモデルの古いバージョンがないことを意味します。これにより、コンポーネントの主要な場所で shouldComponentUpdate
メソッドを定義することにより、インテリジェントな最適化が難しくなります。 (また、 元に戻す のような他の理由でモデルの古いバージョンを簡単に保存する機能を失います。)
forceUpdate
を呼び出すと、単にshouldComponentUpdate
がスキップされ、コンポーネントが強制的に再レンダリングされます。 render
の呼び出しは通常安価であり、Reactはrender
の出力が変更された場合にのみDOMに触れるため、ここでのパフォーマンスの問題はありません。ただし、不変データ(Peteが示唆するようにtoJSON()
から生のモデルプロパティオブジェクトを渡すことを含む)を使用する選択肢がある場合は、強くお勧めします。
より良い答えが出るまで、 quotePete Hunt 、コアReact開発者:
Backboneモデルの大きなメリットは、データフローを管理してくれたことです。
set()
を呼び出すと、データが変更されたことをアプリに通知します。 Reactを使用すると、コールバックおよびReactを介して状態を所有するコンポーネントに通知するだけなので、これはあまり必要ではありません。 _はすべての子が最新であることを保証します。したがって、バックボーンのこの部分はあまり有用ではありません(そして人々はとにかくReactでバックボーンを使用する傾向があります) 。純粋なJSONを渡す必要はありませんが(私はそうする傾向があり、単純なデータモデルではうまく機能します)、オブジェクトを不変に保つと多くの利点が得られます。
バックボーンモデルで
toJSON()
を呼び出すだけで、これを試すことができ、モデルを渡す方法とモデルを渡す方法を確認できます。
(エンファシス鉱山)
興味深いことに、 Backbone.React.Component はtoJSON
を使用する唯一の例ですが、何らかの理由でsetProps
の代わりにsetState
( discouraged too )です。
ピート・ハントのアプローチに基づいて簡単なミックスインを作成しました(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
を新しい値で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+が必要です。
私はBackbone.React.Componentの開発者です。 setPropsを使用する理由は、これがコンポーネント所有者(最大の親)によってのみ呼び出されることを意図しているためです。私の見方では、プロップは状態よりもリアクティブ更新(および子コンポーネントに渡す)に使用する方が良いですが、状態が優れている理由をいくつか指摘していただければ、その変化に向けて開発を開始させていただきます。
例えば、時々transferPropsToが非常に便利な、他の人に委任するコンポーネントがあります。状態を使用すると、それを達成するのが難しくなります。