Detect update in observable prop

裝載自:https://stackoverflow.com/questions/41736558/detect-update-in-observable-prop

Ask Question

up vote1down votefavorite

1

I have a component that has an observable as property:

class Store {
   @observable color = "red" 
}

const store = new Store(); 

@observer
class MyComponent extends React.Component {  
  componentWillReceiveProps(nextProps) {
    // Not called!
    console.log("Component will receive props", nextProps.store.color)
  }
  componentDidMount() {
    console.log("Component did mount", this.props.store.color)  
  }
  changeColor = () => {
    this.props.store.color = (this.props.store.color==="red")? "blue":"red";
  };
  render() {
    return <div>
        color: {this.props.store.color}  
        <button onClick={this.changeColor}>Change color</button>   
    </div>
  }
};

ReactDOM.render(<MyComponent store={store} />, document.body)

My problem is that componentWillReceiveProps is never called when the observed variable is changed (by clicking on the button), nor is componentDidReceiveProps or shouldComponentUpdate. However I can see in the rendered code that the color is indeed changed in the store.

reactjs observable mobx mobx-react

shareimprove this question

edited Jan 21 '17 at 19:00

asked Jan 19 '17 at 7:55

Christopher Chiche

11.4k74385

add a comment

2 Answers

activeoldestvotes

up vote4down vote

tl;dr: use componentWillUpdate and componentDidUpdate


The object Store passed as a prop never changes, even when its content changes. The trick of using @observable is that it will trigger the update in the component without changing the props. So using lifecycle functions such as shouldComponentUpdatecomponentWillReceiveProps and componentDidReceiveProps won't work with since they are triggered when either the component's props or state changes. The mobx doc explains it well in the shouldComponentUpdate section.

So, to catch an update in an observable, we must go a bit deeper in the lifecycle stack and use componentWillUpdate and componentDidUpdate.

So, the code should look like this:

@observer
class MyComponent extends React.Component {  
  componentWillReceiveProps(nextProps) {
    // Not called! 
    console.log("Component will receive props", nextProps.store.color)
  }
  componentWillUpdate(nextProps) {
    console.log("Component will update", nextProps.store.color)
  }
  componentDidMount() {
    console.log("Component did mount", this.props.store.color)  
  }
  changeColor = () => {
    this.props.store.color = (this.props.store.color==="red")? "blue":"red";
  };
  render() {
    return <div>
        color: {this.props.store.color}  
        <button onClick={this.changeColor}>Change color</button>   
    </div>
  }
};

JS Bin: http://jsbin.com/voqugezaya/edit?js,console,output

Under the cover, mobx-react uses the forceUpdate function to trigger the component to re-render without necessarily changing the objects in its props (only their content changes).

Also, there is a new function introduced by mobx, which is quite helpful for debugging: componentWillReact.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章