MobX @inject 保姆级解析:新手也能懂的状态注入

43 阅读5分钟

MobX @inject 保姆级解析:新手也能懂的状态注入

如果你刚接触 MobX,大概率会被 @observable@observer@inject 这些装饰器绕晕。前面我们已经搞懂了“状态响应式”(@observable)和“组件响应状态”(@observer),今天就聚焦 @inject——它到底是干嘛的?什么时候用?怎么用才不踩坑?

全程用“人话+极简示例”,新手直接抄作业就行~

一、先搞懂核心问题:@inject 解决了什么痛点?

在 MobX 里,我们会把“共享状态”(比如用户信息、全局设置)放在一个专门的“仓库”(Store)里,而不是散在各个组件中。但问题来了:

👉 深层嵌套的组件,怎么拿到顶层 Store 里的状态?

总不能一层层往下传 props 吧?(这种“props drilling”的方式,组件层级多了会疯!)

这时候 @inject 就登场了——它的核心作用是:把 Store 直接“注入”到需要的组件里,组件不用通过 props 就能直接用 Store 的状态和方法

举个生活化的例子:Store 是公司的“物资仓库”,组件是各个“部门”。@inject 就像“仓库配送员”,直接把部门需要的物资(状态/方法)送到门口,不用部门一层层向上申请。

二、前置知识:@inject 不能单独用!必须搭配这两个“伙伴”

新手最容易踩的坑:单独写 @inject 没效果!因为它需要两个“帮手”配合:

  1. Provider:“顶层供应商”,负责把 Store 暴露给所有子组件(相当于告诉“配送员”仓库在哪);
  2. @observer:“响应式监听者”,让组件能感知 Store 中状态的变化(相当于部门要有人盯着,物资到了能及时用上)。

三者的关系: Provider(提供 Store) → @inject(注入 Store 到组件) → @observer(组件响应 Store 变化)

三、实战步骤:3步搞定 @inject 用法

我们用“用户信息管理”的极简场景演示:创建一个 UserStore 存储用户名,然后在组件中通过 @inject 使用它。

步骤1:创建 Store(仓库)

首先定义一个 Store 类,用@observable 定义状态,用 @action 定义修改状态的方法(不了解这两个装饰器的可以先记住:observable 是“可观察状态”,action 是“修改状态的正确方式”)。

// stores/UserStore.js
import { observable, action } from "mobx";

class UserStore {
  // 可观察状态:用户名
  @observable username = "未登录";

  // 动作:修改用户名(修改状态必须用 action)
  @action setUsername = (name) => {
    this.username = name;
  };
}

// 导出实例(全局唯一)
export default new UserStore();

步骤2:用 Provider 包裹顶层组件(暴露 Store)

在项目的入口文件(比如 index.js),用 MobX 提供的 Provider 组件把根组件包裹起来,同时把 Store 作为 Provider 的属性传入——这样所有子组件都能“感知”到 Store 的存在。

// index.js
import React from "react";
import ReactDOM from "react-dom/client";
import { Provider } from "mobx-react"; // 导入 Provider
import UserStore from "./stores/UserStore"; // 导入 Store 实例
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  // 用 Provider 包裹根组件,传入 Store
  <Provider userStore={UserStore}>
    <App />
  </Provider>
);

注意:Provider 的属性名(这里是 userStore)可以自定义,后面注入时要对应上。

步骤3:用 @inject 注入 Store 到组件

现在,任何子组件都可以通过 @inject("userStore") 拿到 Store,再搭配 @observer 让组件响应状态变化。

// components/Profile.js
import React from "react";
import { inject, observer } from "mobx-react"; // 导入 inject 和 observer

// 1. @inject("userStore"):注入名为 userStore 的 Store
// 2. @observer:让组件响应 Store 中状态的变化
@inject("userStore")
@observer
class Profile extends React.Component {
  render() {
    // 通过 this.props.userStore 拿到 Store 实例
    const { username, setUsername } = this.props.userStore;

    return (
      <div>
        <p>当前用户:{username}</p>
        <button onClick={() => setUsername("小明")}>
          登录
        </button>
      </div>
    );
  }
}

export default Profile;

然后在 App 组件中直接使用 Profile 就行,不用传任何 props:

// App.js
import React from "react";
import Profile from "./components/Profile";

function App() {
  return (
    <div className="App">
      <h1>MobX @inject 示例</h1>
      <Profile /> {/* 不用传 props! */}
    </div>
  );
}

export default App;

效果演示

页面初始显示“当前用户:未登录”,点击“登录”按钮后,会触发 Store 中的 setUsername 方法,修改 username 状态,组件会自动重新渲染,显示“当前用户:小明”——这就是 @inject + @observer 的完整作用!

四、常见疑问:新手必看

1. 可以注入多个 Store 吗?

当然可以!如果有多个 Store(比如 UserStore、CartStore),只需两步:

  1. Provider 中传入多个 Store:<Provider userStore={UserStore} cartStore={CartStore}>
  2. 组件中注入多个:@inject("userStore", "cartStore")

2. 函数组件怎么用 @inject?

MobX 支持函数组件,用起来更简洁——直接把 inject 作为高阶函数使用:

// components/ProfileFunc.js
import React from "react";
import { inject, observer } from "mobx-react";

// 注入后,Store 会作为 props 传入函数组件
const ProfileFunc = ({ userStore }) => {
  return (
    <div>
      <p>当前用户:{userStore.username}</p>
      <button onClick={() => userStore.setUsername("小红")}>
        切换用户
      </button>
    </div>
  );
};

// 先 inject 再 observer(顺序不能乱!)
export default inject("userStore")(observer(ProfileFunc));

3. 为什么注入后拿不到 Store?

大概率是这3个问题:

  • Provider 没包裹顶层组件:必须确保所有需要注入的组件都在 Provider 内部;
  • 注入的名称和 Provider 的属性名不一致:比如 Provider 传的是 userStore,注入时写了 userstore(大小写敏感);
  • 忘记导出 Store 实例:Store 类要导出实例(export default new UserStore()),而不是导出类本身。

五、核心总结

  1. @inject 的作用:免 props 传递,直接给组件注入 Store,解决深层组件拿不到顶层状态的问题;

  2. 必配组合:Provider(顶层提供 Store)+ @inject(注入)+ @observer(响应变化) ,少一个都不行;

  3. 关键注意:注入的名称要和 Provider 的属性名一致,函数组件使用时注意高阶函数的顺序(先 inject 再 observer)。

其实 @inject 本质就是“依赖注入”的思想,把组件需要的 Store 直接“送上门”,让组件更专注于自己的 UI 逻辑,不用关心状态从哪来。

如果还是没懂,建议把上面的示例代码复制到项目里跑一遍,修改一下状态看看效果——实践出真知!如果有其他疑问,评论区留言哦~