当 render 方法中没有使用 observable 时,如何让 MobX 更新组件?
How to make MobX update the component when observable is not used in the render method?
在从 Redux 切换到 React 的 MobX 之后,我开始非常喜欢 MobX。太棒了。
MobX 有一个特定的行为,如果提供的 store observable 没有在渲染中使用,它不会更新组件。我认为通常这是一种非常棒的行为,它使组件仅在实际发生更改时才呈现。
但是...我确实遇到过一些我不想或不需要在渲染方法中使用 MobX observable 的情况,在这种情况下,我的 this.props.store
与 MobX 商店将不会得到更新。
在这种情况下,作为一种解决方法,我只是在渲染方法中引用可观察对象,但我认为这不是一种非常简洁的方法,我想知道是否有更简洁的方法来做到这一点?
这个组件代码应该可以解释更多我到底在问什么。
它是一个基于我商店中的 MobX 可观察对象更改主体溢出样式的组件。
/*------------------------------------*\
Imports
\*------------------------------------*/
import React from 'react';
import connectStore from 'script/connect-store';
import addClass from 'dom-helpers/class/addClass';
import removeClass from 'dom-helpers/class/removeClass';
/*------------------------------------*\
Component
\*------------------------------------*/
class Component extends React.Component {
constructor(props) {
super(props);
this.constructor.displayName = 'BodyClassSync';
}
componentDidMount() {
this.checkAndUpdateMuiClass();
}
componentDidUpdate() {
this.checkAndUpdateMuiClass();
}
checkAndUpdateMuiClass() {
// This place is the only place I need latest MobX store...
if (this.props.store.muiOverlay) {
addClass(window.document.body, 'mod-mui-overlay');
}
else {
removeClass(window.document.body, 'mod-mui-overlay');
}
}
render() {
// This is my workaround so the componentDidUpdate will actually fire
// (with latest and updated store)
// when the 'muiOverlay' observable changes in the MobX store
// Is there any cleaner/better way to do this?
this.props.store.muiOverlay;
// This component doesn't and shouldn't render anything
return null;
}
}
/*------------------------------------*\
Export
\*------------------------------------*/
const ComponentWithStore = connectStore(Component);
export default ComponentWithStore;
(注意:我不使用@decorators,我在 connectStore 函数中使用 ES5 语法连接商店。如果这个问题的解决方案也在 ES5 中,那就太棒了。)
您可以在 componentDidMount
中使用 autorun 并在 componentWillUnmount
中配置侦听器,这样您就不必在渲染方法中引用它。
class Component extends React.Component {
constructor(props) {
super(props);
this.constructor.displayName = 'BodyClassSync';
}
componentDidMount() {
this.dispose = autorun(() => {
const { muiOverlay } = this.props.store;
if (muiOverlay) {
addClass(window.document.body, 'mod-mui-overlay');
} else {
removeClass(window.document.body, 'mod-mui-overlay');
}
});
}
componentWillUnmount() {
this.dispose();
}
render() {
return null;
}
}
由于您实际上并未在此组件中执行任何操作,因此您也可以将此 autorun
直接放入您的商店中。
不知道我是怎么错过它的,但感谢@Tholle,我重新阅读了 MobX 文档中的 "Reacting to observables" 部分,发现 reaction
助手是最适合我的解决方案。
虽然,reaction
最适合我遇到的确切问题。 autorun
和 when
助手在功能上非常相似,我可能也可以将它们用于我的用例。
https://mobx.js.org/refguide/autorun.html
https://mobx.js.org/refguide/when.html
https://mobx.js.org/refguide/reaction.html
这是代码示例,展示了如何为任何只想快速复制+粘贴的人使用 reaction
:
componentDidMount(){
this._notificationsReactionDispose = mobx.reaction(
() => this.props.store.notifications,
(notifications, reaction) => {
... the code that runs when "notifications" in my store change
}
);
}
componentWillUnmount() {
this._notificationsReactionDispose();
}
在从 Redux 切换到 React 的 MobX 之后,我开始非常喜欢 MobX。太棒了。
MobX 有一个特定的行为,如果提供的 store observable 没有在渲染中使用,它不会更新组件。我认为通常这是一种非常棒的行为,它使组件仅在实际发生更改时才呈现。
但是...我确实遇到过一些我不想或不需要在渲染方法中使用 MobX observable 的情况,在这种情况下,我的 this.props.store
与 MobX 商店将不会得到更新。
在这种情况下,作为一种解决方法,我只是在渲染方法中引用可观察对象,但我认为这不是一种非常简洁的方法,我想知道是否有更简洁的方法来做到这一点?
这个组件代码应该可以解释更多我到底在问什么。 它是一个基于我商店中的 MobX 可观察对象更改主体溢出样式的组件。
/*------------------------------------*\
Imports
\*------------------------------------*/
import React from 'react';
import connectStore from 'script/connect-store';
import addClass from 'dom-helpers/class/addClass';
import removeClass from 'dom-helpers/class/removeClass';
/*------------------------------------*\
Component
\*------------------------------------*/
class Component extends React.Component {
constructor(props) {
super(props);
this.constructor.displayName = 'BodyClassSync';
}
componentDidMount() {
this.checkAndUpdateMuiClass();
}
componentDidUpdate() {
this.checkAndUpdateMuiClass();
}
checkAndUpdateMuiClass() {
// This place is the only place I need latest MobX store...
if (this.props.store.muiOverlay) {
addClass(window.document.body, 'mod-mui-overlay');
}
else {
removeClass(window.document.body, 'mod-mui-overlay');
}
}
render() {
// This is my workaround so the componentDidUpdate will actually fire
// (with latest and updated store)
// when the 'muiOverlay' observable changes in the MobX store
// Is there any cleaner/better way to do this?
this.props.store.muiOverlay;
// This component doesn't and shouldn't render anything
return null;
}
}
/*------------------------------------*\
Export
\*------------------------------------*/
const ComponentWithStore = connectStore(Component);
export default ComponentWithStore;
(注意:我不使用@decorators,我在 connectStore 函数中使用 ES5 语法连接商店。如果这个问题的解决方案也在 ES5 中,那就太棒了。)
您可以在 componentDidMount
中使用 autorun 并在 componentWillUnmount
中配置侦听器,这样您就不必在渲染方法中引用它。
class Component extends React.Component {
constructor(props) {
super(props);
this.constructor.displayName = 'BodyClassSync';
}
componentDidMount() {
this.dispose = autorun(() => {
const { muiOverlay } = this.props.store;
if (muiOverlay) {
addClass(window.document.body, 'mod-mui-overlay');
} else {
removeClass(window.document.body, 'mod-mui-overlay');
}
});
}
componentWillUnmount() {
this.dispose();
}
render() {
return null;
}
}
由于您实际上并未在此组件中执行任何操作,因此您也可以将此 autorun
直接放入您的商店中。
不知道我是怎么错过它的,但感谢@Tholle,我重新阅读了 MobX 文档中的 "Reacting to observables" 部分,发现 reaction
助手是最适合我的解决方案。
虽然,reaction
最适合我遇到的确切问题。 autorun
和 when
助手在功能上非常相似,我可能也可以将它们用于我的用例。
https://mobx.js.org/refguide/autorun.html
https://mobx.js.org/refguide/when.html
https://mobx.js.org/refguide/reaction.html
这是代码示例,展示了如何为任何只想快速复制+粘贴的人使用 reaction
:
componentDidMount(){
this._notificationsReactionDispose = mobx.reaction(
() => this.props.store.notifications,
(notifications, reaction) => {
... the code that runs when "notifications" in my store change
}
);
}
componentWillUnmount() {
this._notificationsReactionDispose();
}