在mobx-state-tree Store中绑定UI窗口属性的最佳方案
嘿,刚好有过类似的实践经验,来给你拆解下在mobx-state-tree(MST)里绑定window.innerHeight这类窗口属性的靠谱方案——你一开始想到用getEnv()的方向完全正确,这也是MST推荐的依赖注入方式,能让你的store更干净、更易测试。下面一步步来:
在Mobx-State-Tree中绑定窗口UI属性的最佳方案
1. 定义管理窗口状态的MST Store
先创建一个专门的窗口状态store(或者把相关字段加到现有根store里),用来存储窗口尺寸这类属性,同时定义更新和监听的action:
import { types, getEnv } from "mobx-state-tree"; const WindowStore = types .model("WindowStore", { innerHeight: types.number, innerWidth: types.number, }) .actions((self) => ({ // 更新窗口尺寸的核心action updateWindowSize() { const { window } = getEnv(self); self.innerHeight = window.innerHeight; self.innerWidth = window.innerWidth; }, // 初始化窗口resize监听的方法 setupResizeListener() { const { window } = getEnv(self); // 先执行一次获取初始尺寸 self.updateWindowSize(); // 给resize事件加防抖,避免拖动窗口时频繁触发更新 const debouncedUpdate = () => { self.updateWindowSize(); }; // 这里可以用lodash的debounce,或者自己写个简单防抖 const handleResize = _.debounce(debouncedUpdate, 100); window.addEventListener("resize", handleResize); // 返回清理函数,方便后续移除监听 return () => { window.removeEventListener("resize", handleResize); }; }, }));
2. 初始化Store时注入Window对象
创建store实例的时候,把真实的window对象注入到MST的环境中,这样store就能通过getEnv()拿到它:
// 可以单独创建窗口store,也可以作为根store的子节点 const windowStore = WindowStore.create({}, { window });
3. 用observer让组件响应状态变化
因为你不熟悉Mobx的observer,简单说它的作用是让组件自动监听Mobx/MST状态的变化,一旦状态更新就重新渲染。用它包裹你的组件,就能实时展示窗口尺寸了:
import { observer } from "mobx-react-lite"; import { windowStore } from "./stores"; const WindowSizeViewer = observer(() => { return ( <div className="window-size-info"> 当前窗口高度: {windowStore.innerHeight}px <br /> 当前窗口宽度: {windowStore.innerWidth}px </div> ); });
4. 在应用入口启动监听并清理
最后在你的根组件里,调用监听方法,并在组件卸载时执行清理,避免内存泄漏:
import { useEffect } from "react"; function App() { useEffect(() => { const cleanupListener = windowStore.setupResizeListener(); // 组件卸载时移除监听 return cleanupListener; }, []); return ( <div className="App"> <WindowSizeViewer /> {/* 其他组件 */} </div> ); }
额外实用小贴士
- 测试友好:因为用了
getEnv(),测试时可以轻松注入模拟的window对象,比如:const mockWindow = { innerHeight: 800, innerWidth: 1200, addEventListener: jest.fn(), removeEventListener: jest.fn() }; const testStore = WindowStore.create({}, { window: mockWindow }); - 性能优化:防抖一定要加,不然窗口拖动时会每秒触发几十次更新,影响页面性能。
- 全局复用:如果你的应用有多个组件需要用到窗口尺寸,可以把WindowStore作为根store的子节点,方便全局访问。
这样一套流程下来,就能完美实现窗口属性和MST store的绑定,同时保持代码的可维护性和可测试性啦~
内容的提问来源于stack exchange,提问作者Nick Gideo
相关产品推荐
相关产品推荐

