2

mobx: 5.03 react: 16.4.1 mobx-react: 5.2.3 rails: 5.0.2 react-rails gem

I have a basic mobx setup in react. I am trying to get the rowData observable variable to change in the view after an http request. However, once it is rendered at the default "111" it always stays at that value. How can I get mobx to update the Component render?

import React from "react"
import axios from 'axios'

import { decorate, observable, computed, action } from "mobx"
import { observer } from "mobx-react"

class Device extends React.Component {
        rowData = 111 //view always stays at this value

        componentDidMount() {
            axios.get("/projects.json")
            .then(response => { this.rowData = 555 }) 
            .then(() => console.log(this.rowData)) //logs 555
        }

        render() {
            return (
                <div>
                    {this.rowData}
                </div> 
            );
        }

}

decorate(Device, {
    rowData: observable
})

export default observer(Device);
GavinBelson
  • 2,514
  • 25
  • 36
  • 1
    [It works for me](https://codesandbox.io/s/62yq40w26z). It might be that your axios request fails. Try adding a `.catch(error => console.error(error))` after the last `then`. – Tholle Jul 24 '18 at 23:07
  • The data changes in your view? – GavinBelson Jul 24 '18 at 23:09
  • Yes, look at the example in the link. You should also write `.then(() => console.log(this.rowData))` or `console.log(this.rowData)` will be run before your request, which is not what you want. – Tholle Jul 24 '18 at 23:16
  • 1
    Sigh, I copied your code into my app.. still renders the initial 111 value.. Something must be off on my stack.. Rails/react-rails gem/webpack – GavinBelson Jul 24 '18 at 23:22
  • try decorating it with action. `.then(action(response => { this.rowData = 555 }))` – SharpCode Jul 24 '18 at 23:46
  • @Tholle, I think I have a solution after your comment. Why does `.then(() => console.log(this.rowData))` fire after variable mutation, but `.then(console.log(this.rowData))` does not wait? – GavinBelson Jul 25 '18 at 01:32
  • @SharpCode good try, but that one didn't work – GavinBelson Jul 25 '18 at 01:33
  • 1
    When you write `.then(console.log(this.rowData))`, you are invoking `console.log` straight away. It might look a bit more clear if you write `.then(function () { console.log(this.rowData) }.bind(this))` to see the difference. I think [this is a great read on the subject](https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html). – Tholle Jul 25 '18 at 01:38
  • Wow, that is a GREAT read, thanks. Based on that, I can workaround/force a single new render by chaining `.then(() => this.setState({ state: this.state }))` Then the value changes.. If you submit that as an answer, I'll accept.. – GavinBelson Jul 25 '18 at 01:49
  • @HoosierCoder Great that you found the article useful. It's a bummer that you have to use `setState` to get MobX to work, that almost feels like it defeats the whole purpose of MobX. – Tholle Jul 25 '18 at 11:48
  • Did you try let _this = this; _this.rowData; then switch to componentWillMount...? – Jason Mullings May 18 '19 at 13:54
  • I did not, it was something with the react-rails gem that was not working with MOBX. Just had to `setState` in that project. In other projects where front end was decoupled from back end MOBX updating worked perfectly without this workaround. – GavinBelson May 19 '19 at 14:33

1 Answers1

1

Try doing a constructor with this:

constructor(props){
  super(props);
  makeObservable(this, {
    rowData: observable
  });
}

Not sure if those functions are available in 5 though. Might need to upgrade Mobx.

DeltaTango
  • 821
  • 2
  • 9
  • 19