observer
函数 / 装饰器可以将React组件转换为可响应MobX的组件。
它将components的render函数使用 MobX.autorun
包裹,以确保任何依赖数据的更新都会触发重渲染。
它是通过独立的 mobx-react
包提供的。
import {observer} from "mobx-react";
var timerData = observable({
secondsPassed: 0
});
setInterval(() => {
timerData.secondsPassed++;
}, 1000);
@observer class Timer extends React.Component {
render() {
return (<span>Seconds passed: { this.props.timerData.secondsPassed } </span> )
}
});
React.render(<Timer timerData={timerData} />, document.body);
提示:当observer
需要与其他装饰器组合使用时,请确保是最里层(第一个被应用)的装饰器,否则不会有任何效果。
注意@observer
装饰器是可选的,使用 observer(class Timer ... { })
具有同样的效果。
MobX 可以做很多事,但是它不能使原始数据可观察(虽然可以把它们包含在一个对象中,见 boxed observables)。所以它观察的不是对象中的 值,而是 属性。这意味着 observer
实际上响应了你解引用值的事实。所以我们在上面的例子中,如果我们如下初始化,则 Timer
组件 不会 做出响应:
React.render(<Timer timerData={timerData.secondsPassed} />, document.body)
在这段代码里,我们只是把 secondsPassed
的当前值传递给 Timer
,这是不可变得值 0
(JS中所有的原始数据都是不可变的)。这个数字在将来不会再发生改变,所以 Timer
将永远不会更新。属性 secondsPassed
将来会发生改变,所以我们需要在组件 中 访问它。换句话说:值需要通过 引用 传递 而非 值 传递。
在 ES5 环境下,observer 组件可以简单的通过使用 observer(React.createClass({ ...
声明。另请参考 syntax guide
上面的 Timer 组件也可以通过给 observer
传递无状态函数进行编写:
import {observer} from "mobx-react";
const Timer = observer(({ timerData }) =>
<span>Seconds passed: { timerData.secondsPassed } </span>
);
就像正常的类一样,你可以在组件中使用 @observable
装饰器引入可观察的属性。这意味着你可以有组件自己的本地状态,而且不需要React的冗余和强制的 setState
机制来管理它,它是非常强大的。响应状态将由 render
接收,而不会显式的调用React的生命周期方法如 componentShouldUpdate
或 componentWillUpdate
。如果你需要她们,只需正常使用React基于 state
的APIs即可。
上面的例子也可以写成:
import {observer} from "mobx-react"
import {observable} from "MobX"
@observer class Timer extends React.Component {
@observable secondsPassed = 0
componentWillMount() {
setInterval(() => {
this.secondsPassed++
}, 1000)
}
render() {
return (<span>Seconds passed: { this.secondsPassed } </span> )
}
})
React.render(<Timer />, document.body)
对于使用可被观察的组件局部状态有很多优点,具体详见 我们为什么要停止使用setState
observer
连接到 storesmobx-react
包也提供了 Provider
组件,可以用于使用React的上下文机制来传递stores。为了连接多个stores,可以传递一个store名称的数组参数给 observer
,它会把这些stores变成props。当使用装饰器(@observer(["store"]) class ...
)或者 observer(["store"], React.createClass({ ...
方法也是支持的。
例如:
const colors = observable({
foreground: '#000',
background: '#fff'
});
const App = () =>
<Provider colors={colors}>
<app stuff... />
</Provider>;
const Button = observer(["colors"], ({ colors, label, onClick }) =>
<button style={{
color: colors.foreground,
backgroundColor: colors.background
}}
onClick={onClick}
>{label}<button>
);
// later..
colors.foreground = 'blue';
// 所有按钮都更新了
更多信息请查阅 mobx-react
文档.
observer
?这里有一个简单的原则:所有使用可观察数据渲染的组件。如果你不想把这个组件标记为观察者,例如为了减少通用组件库的依赖,请确保你传递的只是纯粹的数据。
通过使用 @observer
,我们就不需要为了渲染的目的区分智能(smart)组件和木偶(dump)组件。它仍然是一个很好的分离,我们只需关注在哪里处理事件,发起请求等。当它们 自身 的依赖发生变化时,所有的组件都负责更新。它的开销是可以忽略的,它可以确保每当你使用可观察的数据时,组件将会根据它响应。更多信息请参阅 thread
observer
和 PureRenderMixin
observer
阻止 props 浅改变时的重新渲染,这使得传递到组件的数据是具有响应性的,这是非常有意义的。这个行为和 React PureRender mixin 是非常相似的,除了仍然需要处理状态改变。如果一个组件提供了它自己的 shouldComponentUpdate
函数,那么这个函数的优先级更高。可以参阅这个解释 github issue
componentWillReact
(生命周期钩子)React组件通常在一个新的堆栈上渲染,这使得它经常很难弄清楚到底是什么 导致 了组件的重新渲染。当使用mobx-react
时,你可以定义一个新的生命周期钩子,当一个组件准备重新渲染时,componentWillReact
(双关语)将会被触发,因为它观察到的数据已经发生了变化。这使得它很容易的追踪到什么造成了组件的重新渲染。
import {observer} from "mobx-react";
@observer class TodoView extends React.Component {
componentWillReact() {
console.log("我会重渲染, 当todo改变的时候!");
}
render() {
return <div>this.props.todo.title</div>;
}
}
componentWillReact
没有参数componentWillReact
初始化 render 之前不会被触发(可使用 componentWillMount
取代)componentWillReact
当接收到新的 props 或调用 setState
之后不会被触发(可使用 componentWillUpdate
替代)请参阅相关 章节.
@observer
与 PureRenderMixin
实现 shouldCompoentUpdate
的方式一样,所以其子元素没有重新进行渲染的必要。@observer
不依赖于 React 的上下文系统。装饰器语法默认是不被支持的。
--experimentalDecorators
这一构建工具标记,并在 tsconfig.json
中将experimentalDecorators
设置为 true
(推荐)。--stage 0
传给了Babel CLI