为什么我需要在 MobX 中使用 Context 或 Provider?

Rem*_*ich 18 reactjs mobx mobx-react

我正在尝试学习如何在 React 中使用 MobX,但我不明白为什么需要使用 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);
Run Code Online (Sandbox Code Playgroud)

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

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;
Run Code Online (Sandbox Code Playgroud)

使用上下文也有效:

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;
Run Code Online (Sandbox Code Playgroud)

(我正在使用 create-react-app 加上 mobx、mobx-react,即 React 16.9.0 与 MobX 5.13.0 和 mobx-react 6.1.3)

请注意,存储创建一次,从那时起它始终保持相同的对象。

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

仅仅是关于可测试性吗?

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

Iva*_* V. 9

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

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

如果你真的不喜欢使用,React.context你也可以使用服务定位器模式代替(但基本上是一样的)

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>
  )
})
Run Code Online (Sandbox Code Playgroud)

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

持有用道具建造的商店的建议最佳实践


Vip*_*dav 3

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

提供者允许使用组件订阅上下文更改。

在 Mobx 中,我们在顶层使用提供程序将所有存储实例传递给用提供程序包装的所有子组件,例如

import { Provider } from "mobx-react";


<Provider {...Stores}>
   <App/>
 </Provider>
Run Code Online (Sandbox Code Playgroud)

现在我们可以使用注入 Hoc 来访问子组件内的所有存储属性作为 props,例如

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

export default inject("app")(App);
Run Code Online (Sandbox Code Playgroud)

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

inject(stores => ({
 abc: stores.abc,
 bca: stores.bca
}))
Run Code Online (Sandbox Code Playgroud)

因此它将解决直接在组件中导入商店的问题,这也是 mobx 不推荐的

  • 但这并不能回答我的问题。我的问题是 *为什么* MobX 不推荐它?请注意,您的提供程序/注入方式不再是 mobx-react 推荐的方式,他们建议像我一样使用 Context 。但为什么*? (14认同)