为什么 mobx 需要动作,为什么不只是将所有突变批处理到 setImmediate 中?
Why mobx needs actions, why not just to batch all mutations into setImmediate?
开始学习mobx,不明白mobx为什么要发明"actions"实体。将所有更改批处理到 setImmediate 中的下一个滴答中会更容易吗?这将自动使所有同步状态更改以与 @action 现在相同的方式进行。在动作完成后立即触发观察者而不是在下一个 tick 内触发观察者是否有任何好处?
根据 https://github.com/mobxjs/mobx/issues/1523 的对话:
- setImmediate 仅在 IE 和 Nodejs 中实现。 setTimeout(fn, 0) 会造成 4 毫秒的延迟
- https://hackernoon.com/the-fundamental-principles-behind-mobx-7a725f71f3e8:异步更新不会有很好的堆栈跟踪来查找触发该更新的人
- React 仅批处理来自事件侦听器的 setState 调用,mobx-react couple 也是如此。这意味着React组件不会在mutation后立即重新渲染,它只会在事件监听器回调后同步更新。
几个示例(所有 jsx 组件都应该在 @observer
内):
// Ok to do this
<input value={appState.name} onChange={e => appState.name = e.target.value}/>
// Ok too, will rerender only once
<input value={appState.name} onChange={e => {
appState.name = e.target.value;
appState.foo = appState.foo + 1;
}}/>
// Not very good, will rerender twice on each click.
// Nevertheless, I do not know why someone will do this
<button onClick={() => {
setTimeout(() => {
appState.foo = appState.foo + 1;
appState.bar = appState.bar + 10;
}, 0);
}}>Click me foo={appState.foo} bar={appState.bar}</button>
// But that way it will rerender once and show console output only once too
autorun(() => console.info(`App state foo={appState.foo} bar={appState.bar}`));
<button onClick={() => {
setTimeout(() => {
runInAction(() => {
appState.bar = appState.bar + 10;
appState.foo = appState.foo + 1;
})
}, 0);
}}>Click me foo={appState.foo} bar={appState.bar}</button>
// That code will show console output twice, but rerender only once
autorun(() => console.info(`App state foo={appState.foo} bar={appState.bar}`));
<button onClick={() => {
setTimeout(() => {
ReactDOM.unstable_batchedUpdates(() => {
appState.bar = appState.bar + 10;
appState.foo = appState.foo + 1;
})
}, 0);
}}>Click me foo={appState.foo} bar={appState.bar}</button>
开始学习mobx,不明白mobx为什么要发明"actions"实体。将所有更改批处理到 setImmediate 中的下一个滴答中会更容易吗?这将自动使所有同步状态更改以与 @action 现在相同的方式进行。在动作完成后立即触发观察者而不是在下一个 tick 内触发观察者是否有任何好处?
根据 https://github.com/mobxjs/mobx/issues/1523 的对话:
- setImmediate 仅在 IE 和 Nodejs 中实现。 setTimeout(fn, 0) 会造成 4 毫秒的延迟
- https://hackernoon.com/the-fundamental-principles-behind-mobx-7a725f71f3e8:异步更新不会有很好的堆栈跟踪来查找触发该更新的人
- React 仅批处理来自事件侦听器的 setState 调用,mobx-react couple 也是如此。这意味着React组件不会在mutation后立即重新渲染,它只会在事件监听器回调后同步更新。
几个示例(所有 jsx 组件都应该在 @observer
内):
// Ok to do this
<input value={appState.name} onChange={e => appState.name = e.target.value}/>
// Ok too, will rerender only once
<input value={appState.name} onChange={e => {
appState.name = e.target.value;
appState.foo = appState.foo + 1;
}}/>
// Not very good, will rerender twice on each click.
// Nevertheless, I do not know why someone will do this
<button onClick={() => {
setTimeout(() => {
appState.foo = appState.foo + 1;
appState.bar = appState.bar + 10;
}, 0);
}}>Click me foo={appState.foo} bar={appState.bar}</button>
// But that way it will rerender once and show console output only once too
autorun(() => console.info(`App state foo={appState.foo} bar={appState.bar}`));
<button onClick={() => {
setTimeout(() => {
runInAction(() => {
appState.bar = appState.bar + 10;
appState.foo = appState.foo + 1;
})
}, 0);
}}>Click me foo={appState.foo} bar={appState.bar}</button>
// That code will show console output twice, but rerender only once
autorun(() => console.info(`App state foo={appState.foo} bar={appState.bar}`));
<button onClick={() => {
setTimeout(() => {
ReactDOM.unstable_batchedUpdates(() => {
appState.bar = appState.bar + 10;
appState.foo = appState.foo + 1;
})
}, 0);
}}>Click me foo={appState.foo} bar={appState.bar}</button>