You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:13:28