useStores-基于 useContext 对 Mobx 进行封装并全局管理 React 状态

3,001 阅读3分钟

前言

在理解状态管理的概念之前,你必须认识到什么是状态。在 React 中,状态就是你的应用程序的数据层。当谈到 React 和帮助它管理状态的库时,你可以说状态是一个包含你的应用程序正在处理的数据的对象。例如,如果你想在你的应用程序上显示一个项目列表,则状态将包含你打算要显示的项目。状态会影响 React 组件的行为和渲染方式。是的!仅此而已,就这么简单。

因此,状态管理意味着监控和管理您的应用的数据(即状态)。几乎所有的应用程序都有这样或那样的状态,因此,管理状态已成为当今构建任何现代应用程序的最重要部分之一。

当你考虑 React 应用中的状态管理时,基本上有三种选择:

Mobx

我工作中使用 Mobx 作为 React 应用的状态管理库,Mobx 不仅仅适用于 React,它也可以与其他为 Web 应用程序提供动力的 JavaScript 库和框架一起使用。本章将封装一个全局管理 React 应用状态的自定义钩子函数。

  • 仓库地址,基于create-react-app创建,创建过程及相关依赖如下:
    1. npx create-react-app react-use-mobx --template typescript
    2. npm i mobx mobx-react axios

封装过程

storescontexthooks 这三个文件夹根目录下暴露一个 index.ts 的入口文件,通过此入口将相关函数进行导出

  1. 假设应用有两个需要进行管理的商店 CounterStoreThemeStore,新建 src/stores/文件夹

    通过使用 makeAutoObservable 这个 Mobx 提供的 API 将相关属性进行包装,返回一个可观察的对象。

    • src/stores/CounterStore/index.ts

      import { makeAutoObservable } from 'mobx';
      
      export default function CounterStore() {
        return makeAutoObservable({
          count: 0,
          increment() {
            this.count++;
          },
          decrement() {
            this.count--;
          },
          get doubleCount() {
            return this.count * 2;
          },
        });
      }
      
    • src/stores/ThemeStore/index.ts

      import { makeAutoObservable } from 'mobx';
      
      type ThemeStyle = 'light' | 'dark';
      
      export default function ThemeStore() {
        return makeAutoObservable({
          theme: 'light',
          setTheme(newTheme: ThemeStyle) {
            this.theme = newTheme;
          },
        });
      }
      
  2. 使用React.createContext创建一个storesContext,新建src/contexts/文件夹

    • src/contexts/storesContext/index.tsx

      import React from 'react';
      import { CounterStore, ThemeStore } from '../../stores';
      
      const storesContext = React.createContext({
        counterStore: CounterStore(),
        themeStore: ThemeStore(),
      });
      
      export default storesContext;
      
  3. 编写一个自定义钩子函数useStores来访问导出的storesContext上下文对象,新建src/hooks文件夹

    • src/hooks/useStores/index.ts

      import React from 'react';
      import { storesContext } from '../../contexts';
      
      const useStores = () => React.useContext(storesContext);
      
      export default useStores;
      
  4. 前三步完成了 store 的编写,将其添加为上下文对象的属性,最后编写自定义钩子函数将上下文对象进行导出。现在我们已经准备好开始消费和使用我们的 store 数据了,新建src/components文件夹

    • src/components/Counter/index.tsx

      import React from 'react';
      import { observer } from 'mobx-react';
      import { useStores } from '../../hooks';
      
      const Counter: React.FC = () => {
        const { counterStore } = useStores();
      
        return (
          <>
            <div>{counterStore.count}</div>
            <button onClick={() => counterStore.increment()}>++</button>
            <button onClick={() => counterStore.decrement()}>--</button>
          </>
        );
      };
      
      export default observer(Counter);
      
    • src/components/ThemeToggler/index.tsx

      import { observer } from 'mobx-react';
      import { useStores } from '../../hooks';
      
      const ThemeToggler = () => {
        const { themeStore } = useStores();
      
        return (
          <>
            <div>{themeStore.theme}</div>
            <button onClick={() => themeStore.setTheme('light')}>白天</button>
            <button onClick={() => themeStore.setTheme('dark')}>黑夜</button>
          </>
        );
      };
      export default observer(ThemeToggler);
      

    在组件中引入自定义钩子函数,并通过解构赋值的方式将组件需要使用到的 store 进行声明,这样就可以在组件内需要的地方消费 store 提供的数据了。

  5. 最后将组件进行挂载

    src/App.tsx

    import React from 'react';
    import Counter from './components/Counter';
    import ThemeToggler from './components/ThemeToggler';
    
    function App() {
      return (
        <div className="App">
          <main>
            <Counter />
            <ThemeToggler />
          </main>
        </div>
      );
    }
    
    export default App;
    

    通过执行npm run start打开的localhost:3000端口,可以看到数据成功展示,此时点击 count 加减按钮可以修改数据的状态,点击主题切换按钮也可以正确的切换主题。

    至此,通过React.useContext这个 API 与 Mobx 的结合,我们成功将 Mobx 的商店数据进行封装,并且可以在组件中消费这些数据。

总结

文章主要介绍了怎么在 React 应用中使用 Mobx 进行状态管理,你可以根据文中的配置步骤,搭建一个集成了 Mobx 的 React App、形象化的理解 Mobx 中重要的概念 (观察者模式),在 React 上的状态管理方面,MobX 可能没有 Redux 那么受欢迎,但它非常成熟,易于上手,并提供了一种无缝集成到新的或现有应用程序中的方法。