Mobx: hack for componentWillMount in stateless components?

Created on 15 Mar 2016  路  1Comment  路  Source: mobxjs/mobx

With mobx, almost all my react components are stateless which works beautifully.

Is there a way to mock componentWillMount in stateless components? I'm trying to do something like this (notice the immediate call to getGif()) but I get error: is not possible to change the value of the state while a computed value is being evaluated (something like that)

const model = observable({
  imgUrl: ''
})

const view = observer( ({state = model, title = 'Random Gif', id = '#gifImg'}) => {

  const getGif = () => {
    state.imgStatus = ': Loading'
    request
    .get('http://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=funny+cats')
    .end( (err, res) => state.imgUrl = res.body.data.image_original_url )
  }
  getGif()

  return div(id, [
    h2( title ),
    img( {src: state.imgUrl } ),
    button( { onClick: getGif }, 'More Please')
  ])
})

Most helpful comment

@rickmed I think in this example getGif will run on each render of your component, so that is significantly different behavior then just running on component will mount. The error you get is the similar to the one you would get from react when trying to change the components state in a render method. Although mobx provides an option to supress, I strongly recommend against it because it makes render conceptually impure.

That being said, you could define your own component constructor that could look like this:

function simpleComponent(componentWillMountFunc, renderFunc) {
  return observer(React.createClass({
    displayName: renderFunc.name,
    render: function() { renderFunc(this.props); }
    componentWillMount: function() {  componentWillMountFunc(this.props); }
  }));
}

const view = simpleComponent(
  ({state = model}) => {
    state.imgStatus = ': Loading'
    request
      .get('http://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=funny+cats')
      .end( (err, res) => state.imgUrl = res.body.data.image_original_url )
  },
  ({state = model, title = 'Random Gif', id = '#gifImg'}) =>
    div(id, [
      h2( title ),
      img( {src: state.imgUrl } ),
      button( { onClick: getGif }, 'More Please')
    ])
)

>All comments

@rickmed I think in this example getGif will run on each render of your component, so that is significantly different behavior then just running on component will mount. The error you get is the similar to the one you would get from react when trying to change the components state in a render method. Although mobx provides an option to supress, I strongly recommend against it because it makes render conceptually impure.

That being said, you could define your own component constructor that could look like this:

function simpleComponent(componentWillMountFunc, renderFunc) {
  return observer(React.createClass({
    displayName: renderFunc.name,
    render: function() { renderFunc(this.props); }
    componentWillMount: function() {  componentWillMountFunc(this.props); }
  }));
}

const view = simpleComponent(
  ({state = model}) => {
    state.imgStatus = ': Loading'
    request
      .get('http://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=funny+cats')
      .end( (err, res) => state.imgUrl = res.body.data.image_original_url )
  },
  ({state = model, title = 'Random Gif', id = '#gifImg'}) =>
    div(id, [
      h2( title ),
      img( {src: state.imgUrl } ),
      button( { onClick: getGif }, 'More Please')
    ])
)
Was this page helpful?
0 / 5 - 0 ratings