MobX observable 未被跟踪

MobX observable not being tracked

我对使用 MobX 还很陌生,一直在尝试用它来检测 window 我的 React-Typescript 应用程序中的调整大小事件。这是我的代码:

App.tsx:

import { computed } from "mobx";
import { observer } from "mobx-react";
import type { Breakpoint } from "./display_size_observer";
import { DisplaySizeObserver } from "./display_size_observer";
import "./styles.css";

const ChildComponent = ({ size }: { size: Breakpoint }) => {
  return <p>Size: {size}</p>;
};

export default function App() {
  const displaySize = computed(() => DisplaySizeObserver.size);
  const Child = observer(() => <ChildComponent size={displaySize.get()} />);
  return <Child />;
}

display_size_observer.ts:

import { observable, action } from "mobx";

export type Breakpoint = "small" | "medium" | "large";

const BreakpointSmall: number = 375;
const BreakpointMedium: number = 768;

const getSizeAsBreakpoint = (size: number) => {
  if (size <= BreakpointSmall) {
    return "small";
  } else if (size <= BreakpointMedium) {
    return "medium";
  }
  return "large";
};

const getWindowSize = () => {
  return getSizeAsBreakpoint(window.innerWidth);
};

const DisplaySizeObserverFactory = (() => {
  let instance: DisplaySizeObserver;

  class DisplaySizeObserver {
    @observable.ref
    size: Breakpoint = getWindowSize();

    constructor() {
      window.addEventListener("resize", this.handleResize);
    }

    @action
    private handleResize() {
      const newSize = getWindowSize();
      if (!this.size || this.size !== newSize) {
        this.size = newSize;
        console.log("Updating size to:", this.size);
      }
    }
  }

  return {
    getInstance: () => {
      if (!instance) {
        instance = new DisplaySizeObserver();
      }
      return instance;
    }
  };
})();

export const DisplaySizeObserver = DisplaySizeObserverFactory.getInstance();

Link 到 codesandbox: https://codesandbox.io/s/admiring-mendel-h0kcb?file=/src/display_size_observer.ts:0-1169&resolutionWidth=446&resolutionHeight=675

根据我的理解,ChildComponentobserver 中应该跟踪显示大小的更新并相应地重新呈现 Child。然而,这似乎并没有发生。

如果能帮助我理解我做错了什么以及如何解决它,我将不胜感激。

有几处出错了:

  1. 在 class 构造函数中添加 makeObservable(this);。从 MobX v6 开始它是必需的。更多信息:

  2. handleResize 函数在此处丢失上下文:window.addEventListener('resize', this.handleResize);,因为它既不是绑定函数也不是箭头函数。使其成为箭头函数。

  3. 不要用@observable.ref代替size@observable就够了

  4. 每个使用 observable 值的组件都应该包装到 observer HOC 中。不要做你在应用程序中做的这些奇怪的事情,就像那样重写它:

const ChildComponent = observer(() => {
  return <p>Size: {DisplaySizeObserver.size}</p>;
});

export default function App() {
  return <ChildComponent />;
}

或者如果你想让 ChildComponent 接受 props 然后将 App 包装在 observer 中并只传递 props:

const App = observer(() => {
  return <ChildComponent size={DisplaySizeObserver.size} />;
})

export default App

Working example on Codesandbox