装载自:https://stackoverflow.com/questions/41736558/detect-update-in-observable-prop
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
asked Jan 19 '17 at 7:55
11.4k74385
add a comment
2 Answers
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 shouldComponentUpdate
, componentWillReceiveProps
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
.