Mobx: Styling with MobX

Created on 11 Sep 2016  ·  6Comments  ·  Source: mobxjs/mobx

I'm pretty sure the root cause of this issue has already been explained multiple times in other places but I'm completely clueless what to search for.

I am trying to observe a style object like this:

import React from 'react'
import { observable } from 'mobx'
import { observer } from 'mobx-react'

@observer
class App extends React.Component {
  @observable
  styles = {
    background: 'blue'
  }

  render () {
    return (
      <div style={this.styles}>Hello world!</div>
    )
  }
}

Sadly MobX won't react to changes on the this.styles.background property. I assume that's because this.styles.background is not used anywhere explicitely but rather only this.styles.

Is this related to the several "deep observing" questions? Or can I do anything to get around this behaviour (apart from just re-listing every single style property in the render method)?

Most helpful comment

All 6 comments

This doesn't work because your style.background is used by the div component (which is not an @observer), not by the App component itself (which only uses the reference to the styles object).

Some simple solutions:

  1. Convert the styles to a plain object in the App component already, e.g. style={toJS(this.styles)} or style={Object.assign({}, this.styles)}
  2. explicityly assign the style properties {{ background: this.styles.background }}
  3. always update the reference to styles itself by creating a new object: this.styles = { background: 'red'}

See: http://jsbin.com/kayeqi/edit?js,output

Thanks for your quick answer!
Okay, seems that your first suggestion works like a charm.
Do you have any material worth reading on _why_ this actually works? (i. e. why the div component is now rerendered on style property change?)

Thanks for the link @andykog, certainly worth reading. I couldn't find what I was looking for (I'm not yet entirely through the article though) but I think after reading @mweststrate's comment for the fifth time I finally got it:

Without toJS() I just pass a reference to this.styles to the div component without letting App know about the concrete this.styles.background property.
toJS() on the other hand walks over the properties of this.styles to convert it to a plain object, meaning that the this.styles.background property now counts as "used by App component" because it's indirectly referenced through the toJs() function.

Did I get that right?

EDIT: Seems I was pausing my read of the article just before hitting the right spot – "use" an observable but without accessing any of its properties.
This seems intuitive to me, still it would be nice to hear if my assumptions on _why_ toJS() fixes this were correct. :)

Exactly, it is now accessed by App, which re-render will also cause the div to be rerendered, while in the old situation div itself was not able to detect the change for the lack of being an observer

Nice, I got it. :)
Thank you both for your efforts! 👍

Was this page helpful?
0 / 5 - 0 ratings