为什么 MobX v6.x 在 React with Typescript 中不能像预期的那样工作?
Why doesn't MobX v6.x work as expected in React with Typescript?
我目前正在编写一个 React 应用程序,它应该能够在任何可观察值发生变化时重新呈现组件。问题是,如果它发生变化,我无法 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
钩子的示例,但我必须使用 class 组件。我不确定为什么这不再调用渲染函数。我安装了 mobx
和 mobx-react
。
尝试不解构 email
字段:
render() {
return <div>{this.props.exampleStore!.email}</div>;
}
你在使用 MobX 6 吗?
Decorator 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/httpsWhosebugcomquestions64268663-9fz6b?file=/src/App.js
就像 Danila 提到的那样,您可能会点击 the change in MobX v6,您必须通过在 makeObservable
或 makeAutoObservable
=29=]构造函数:
class ExampleStore {
constructor() {
makeObservable(this);
}
@observable email = "hello";
[...]
}
不过我不是很喜欢这种变化。这与添加构造函数 + 函数调用的额外步骤无关(对于 classes,否则不需要它);它与此有更多关系,这意味着我总是必须“检查 class”以确保我已经为我添加的字段装饰器添加了“激活调用”。换句话说,它将“使该字段可观察”的操作分成两部分,有时相隔很远。
所以无论如何,我的解决方案是包装 @observable
装饰器,并让它检查构造函数的源代码以确保正在进行调用:(性能影响几乎没有,因为它只是在定义 class)
时运行
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";
[...]
}
唯一的区别是现在,如果我忘记为 class 添加 makeObservable(this);
调用,而我为其添加了 @obs
装饰器,我会收到一条警告消息。
我目前正在编写一个 React 应用程序,它应该能够在任何可观察值发生变化时重新呈现组件。问题是,如果它发生变化,我无法 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
钩子的示例,但我必须使用 class 组件。我不确定为什么这不再调用渲染函数。我安装了 mobx
和 mobx-react
。
尝试不解构 email
字段:
render() {
return <div>{this.props.exampleStore!.email}</div>;
}
你在使用 MobX 6 吗?
Decorator 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/httpsWhosebugcomquestions64268663-9fz6b?file=/src/App.js
就像 Danila 提到的那样,您可能会点击 the change in MobX v6,您必须通过在 makeObservable
或 makeAutoObservable
=29=]构造函数:
class ExampleStore {
constructor() {
makeObservable(this);
}
@observable email = "hello";
[...]
}
不过我不是很喜欢这种变化。这与添加构造函数 + 函数调用的额外步骤无关(对于 classes,否则不需要它);它与此有更多关系,这意味着我总是必须“检查 class”以确保我已经为我添加的字段装饰器添加了“激活调用”。换句话说,它将“使该字段可观察”的操作分成两部分,有时相隔很远。
所以无论如何,我的解决方案是包装 @observable
装饰器,并让它检查构造函数的源代码以确保正在进行调用:(性能影响几乎没有,因为它只是在定义 class)
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";
[...]
}
唯一的区别是现在,如果我忘记为 class 添加 makeObservable(this);
调用,而我为其添加了 @obs
装饰器,我会收到一条警告消息。