【问题标题】:Why do I need to use Context or a Provider with MobX?为什么我需要在 MobX 中使用 Context 或 Provider?
【发布时间】:2019-12-26 15:04:54
【问题描述】:

我正在尝试学习如何将 MobX 与 React 一起使用,但我不明白为什么需要使用 Provider 或 Context,如果持有状态的对象永远不会改变,只会改变它的内容。

例如我在 store.js 中有一个商店(一个随时间变化的简单计时器):

import { decorate, observable, action } from 'mobx';
import React from 'react';

class TheTimer {
    currentTick = 0; // In seconds since start

    tick = () => {
        this.currentTick = Math.floor(performance.now() / 1000);
    }
}

decorate(TheTimer, {
    currentTick: observable,
    tick: action
});

// Bare store
export const timerStore = new TheTimer();
// Store as React context
export const TimerStoreContext = React.createContext(timerStore);

// This makes the timer go
setInterval(timerStore.tick, 100);

现在在组件中使用裸存储已经没有问题了:

import React from 'react';
import { configure } from 'mobx';
import { observer } from 'mobx-react';

import { timerStore } from './store';

configure({ enforceActions: 'observed' });

const App = observer(() => {
    return (
        <p>{timerStore.currentTick}</p>
    );
});

export default App;

使用上下文也可以:

import React from 'react';
import { configure } from 'mobx';
import { observer } from 'mobx-react';

import { TimerStoreContext } from './store';

configure({ enforceActions: 'observed' });

const App = observer(() => {
    const timerStore = React.useContext(TimerStoreContext);

    return (
        <p>{timerStore.currentTick}</p>
    );
});

export default App;

(我使用的是 create-react-app 加 mobx,mobx-react,即 React 16.9.0 与 MobX 5.13.0 和 mobx-react 6.1.3)

请注意,商店只创建一次,从那时起,它始终保持同一个对象。

为什么在将 store 直接用作全局变量时,每个人(或旧的基于 mobx-react Provider 的解决方案)都使用 Context 也有效?

仅仅是可测试性吗?

请注意,我也有不是 React 的 JS 代码,应用程序通过 Websockets 与服务器通信,来自服务器的更新也会导致调用动作;我计划为此使用裸存储,因为该代码位于 React 组件之外。

【问题讨论】:

    标签: reactjs mobx mobx-react


    【解决方案1】:

    上下文主要用于当一些数据需要被不同嵌套级别的许多组件访问时。谨慎应用它,因为它使组件重用变得更加困难。

    Provider 允许消费组件订阅上下文更改。

    在 Mobx 中,我们在顶层使用提供者将所有商店实例传递给使用 Provider 包装的所有子组件,例如

    import { Provider } from "mobx-react";
    
    
    <Provider {...Stores}>
       <App/>
     </Provider>
    

    现在我们可以通过使用inject Hoc来访问子组件内的所有存储属性,例如

    class App extends Component {
      render() {
        return <div>app</div>;
      }
    }
    
    export default inject("app")(App);
    

    您还可以使用inject Hoc 注入多个存储来访问存储在多个存储中的属性

    inject(stores => ({
     abc: stores.abc,
     bca: stores.bca
    }))
    

    这样就解决了mobx也不推荐直接在component里面导入store的问题

    【讨论】:

    • 但这并不能回答我的问题。我的问题是为什么 MobX 不推荐它?请注意,您的 Provider / injection 方式不再是 mobx-react 推荐的方式,他们建议像我一样使用 Context 。但是,为什么
    • 问题是它是一个类似的概念,就像在任何面向对象的编程语言中制作私有变量一样,以便其他类无法直接访问和更改它。
    【解决方案2】:

    前段时间我对这个问题很感兴趣。我从维护者那里得到的答案是因为代码的可测试性

    使用您示例中的代码,您基本上将TheTimer 类视为单例。

    如果您真的不喜欢使用React.context,您也可以使用service locator pattern(但基本上是一样的)

    export const ListHolder = observer(function(props) {
      const listStore = serviceLocator.get(STORES.LIST_STORE)
      return (
        <div>
          <div className={styles.wrap}>
            {listStore.lists.map(list => {
              return <List key={list.id} list={list} />
            })}
          </div>
        </div>
      )
    })
    

    还可以看看 MobX 存储库上关于这个问题的冗长而有趣的讨论。

    suggested best practice for holding onto a store constructed with props

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多