MobX @inject 保姆级解析:新手也能懂的状态注入
如果你刚接触 MobX,大概率会被 @observable、@observer、@inject 这些装饰器绕晕。前面我们已经搞懂了“状态响应式”(@observable)和“组件响应状态”(@observer),今天就聚焦 @inject——它到底是干嘛的?什么时候用?怎么用才不踩坑?
全程用“人话+极简示例”,新手直接抄作业就行~
一、先搞懂核心问题:@inject 解决了什么痛点?
在 MobX 里,我们会把“共享状态”(比如用户信息、全局设置)放在一个专门的“仓库”(Store)里,而不是散在各个组件中。但问题来了:
👉 深层嵌套的组件,怎么拿到顶层 Store 里的状态?
总不能一层层往下传 props 吧?(这种“props drilling”的方式,组件层级多了会疯!)
这时候 @inject 就登场了——它的核心作用是:把 Store 直接“注入”到需要的组件里,组件不用通过 props 就能直接用 Store 的状态和方法。
举个生活化的例子:Store 是公司的“物资仓库”,组件是各个“部门”。@inject 就像“仓库配送员”,直接把部门需要的物资(状态/方法)送到门口,不用部门一层层向上申请。
二、前置知识:@inject 不能单独用!必须搭配这两个“伙伴”
新手最容易踩的坑:单独写 @inject 没效果!因为它需要两个“帮手”配合:
- Provider:“顶层供应商”,负责把 Store 暴露给所有子组件(相当于告诉“配送员”仓库在哪);
- @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),只需两步:
- Provider 中传入多个 Store:
<Provider userStore={UserStore} cartStore={CartStore}> - 组件中注入多个:
@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()),而不是导出类本身。
五、核心总结
-
@inject 的作用:免 props 传递,直接给组件注入 Store,解决深层组件拿不到顶层状态的问题;
-
必配组合:Provider(顶层提供 Store)+ @inject(注入)+ @observer(响应变化) ,少一个都不行;
-
关键注意:注入的名称要和 Provider 的属性名一致,函数组件使用时注意高阶函数的顺序(先 inject 再 observer)。
其实 @inject 本质就是“依赖注入”的思想,把组件需要的 Store 直接“送上门”,让组件更专注于自己的 UI 逻辑,不用关心状态从哪来。
如果还是没懂,建议把上面的示例代码复制到项目里跑一遍,修改一下状态看看效果——实践出真知!如果有其他疑问,评论区留言哦~