微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么MobX v6.x无法在带有Typescript的React中按预期工作?

如何解决为什么MobX v6.x无法在带有Typescript的React中按预期工作?

我当前正在编写一个React App,当任何可观察到的值发生变化时,它应该能够重新渲染组件。问题是,email更改后将无法重新渲染。

store.ts

export class ExampleStore {
  @observable email = 'hello';

  @action setEmail(email: string) {
    this.email = email;
  }
}

index.tsx

const stores = {
  exampleStore
};

ReactDOM.render(
  <Provider {...stores}>
    <App />
  </Provider>,document.querySelector('#root')
);

App.tsx

interface Props {
  exampleStore?: ExampleStore;
}

@inject('exampleStore')
@observer
export class App extends React.Component<Props,{}> {
  componentDidMount() {
    setInterval(() => {
      this.props.exampleStore!.setEmail(Math.random() * 10 + '');
    },2500);
  }

  render() {
    const { email } = this.props.exampleStore!;
    return <div>{email}</div>;
  }
}

我已经看到许多示例使用useContext钩子,但是我必须使用类组件。我不确定为什么不再次调用render函数。我已经安装了mobxmobx-react

解决方法

您正在使用MobX 6吗?

装饰器API进行了一些更改,现在您需要在构造函数中使用makeObservable方法来实现与以前相同的功能:

class ExampleStore {
  @observable email = "hello";

  constructor() {
    makeObservable(this);
  }

  @action setEmail(email) {
    this.email = email;
  }
}

尽管有新事物可能会让您完全放弃装饰器,makeAutoObservable

class ExampleStore {
  email = "hello2";

  constructor() {
    // Don't need decorators now,just this call
    makeAutoObservable(this);
  }

  setEmail(email) {
    this.email = email;
  }
}

此处有更多信息:https://mobx.js.org/react-integration.html

Codesandbox:https://codesandbox.io/s/httpsstackoverflowcomquestions64268663-9fz6b?file=/src/App.js

,

尝试不破坏email字段:

  render() {
    return <div>{this.props.exampleStore!.email}</div>;
  }
,

就像 Danila 提到的那样,您可能会遇到 the change in MobX v6,您必须通过在类构造函数中调用 makeObservablemakeAutoObservable 来明确地使每个类实例可观察:

class ExampleStore {
    constructor() {
        makeObservable(this);
    }
    @observable email = "hello";
    [...]
}

不过,我并不是很喜欢这种变化。添加构造函数 + 函数调用(对于不需要它的类)的额外步骤不是那么多;它更多地与这意味着我总是必须“检查类”以确保我已经为我添加的字段装饰器添加了“激活调用”。换句话说,它把“使这个领域变得可观察”的动作分成了两部分,这两个部分有时相距很远。

所以无论如何,我对此的解决方案是包装 @observable 装饰器,并让它检查构造函数的源代码以确保正在进行调用:(性能影响几乎没有,因为它只在定义类)

const observableWarningGivenFor = new WeakSet<Function>();
export const obs = ((target: Object,propertyKey: string | symbol)=>{
    if (target.constructor instanceof Function && !target.constructor.toString().includes("makeObservable")) {
        if (!observableWarningGivenFor.has(target.constructor)) {
            console.warn(`The @obs decorator was used on "`
                + target.constructor.name + "." + String(propertyKey)
                + `",but the class is missing the "makeObservable(this);" call.`
                + ` See here for more info: https://mobx.js.org/enabling-decorators.html`);
            observableWarningGivenFor.add(target.constructor);
        }
    }
    return observable(target,propertyKey);
}) as typeof observable;

// copy ".ref",etc. fields from "observable" (not wrapped)
for (const [key,descriptor] of Object.entries(Object.getOwnPropertyDescriptors(observable))) {
    Object.defineProperty(obs,key,descriptor);
}

用法:(和平常一样)

class ExampleStore {
    constructor() {
        makeObservable(this);
    }
    @obs email = "hello";
    [...]
}

唯一的区别是,现在,如果我忘记为添加了 makeObservable(this); 装饰器的类添加 @obs 调用,我会收到一条警告消息。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。