Facebook React encourages you to separate mutable (state
) and immutable (props
) state:
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.
There is a way to trigger DOM update manually by calling forceUpdate
but it is discouraged:
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.
However, all React+Backbone examples I have seen ignore this advice and store models and collections in props
and call 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/
Even React's own example uses forceUpdate
:
Is there a better way, though, and what benefits would it give?
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.
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.
Until there is a better answer, let me quote Pete Hunt, a core React developer:
(emphasis mine)
Interestingly, Backbone.React.Component is the only example I found that uses
toJSON
, but for some reason also usessetProps
instead ofsetState
(which is discouraged too).Update
I made a simple mixin based on Pete Hunt's approach (no
setProps
, noforceUpdate
):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 intostate
. You need to overridegetBackboneState(props)
for this to work, and optionallywatchBackboneProps
to tell the mixin when to callsetState
with fresh values.Usage example:
Note: mixin requires Underscore 1.6.0+.
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.)Calling
forceUpdate
merely skipsshouldComponentUpdate
and forces the component to rerender. Note that callingrender
is usually cheap, and React will still only touch the DOM if the output ofrender
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 fromtoJSON()
as Pete suggests), I'd highly recommend it.