如何解决如何使用 React + TypeScript 从 MobX 5 迁移到 MobX 6,而不添加具有 200% 语法噪音的臃肿代码?
我正在尝试将我的 TypeScript/create-react-app 应用程序从 MobX 5 迁移到 MobX 6。在官方迁移指南 (https://mobx.js.org/migrating-from-4-or-5.html#upgrading-classes-to-use-makeobservable) 中,他们建议如下:
移除所有装饰器并在构造函数中调用 makeObservable 和 明确定义应该使用哪个字段使哪个字段可观察 装饰器。
但他们没有说明如何使用 TypeScript 应用程序执行此操作。给出的示例总是直接使用纯 JavaScript 和 React.RenderDOM
。
这是一个简化示例的开始 - 我需要迁移的典型类:
@observer
export default class LoginPage extends React.Component<ILoginPageProps,{}> {
@observable private email: string = process.env.REACT_APP_DEFAULT_LOGIN_EMAIL || "";
@observable private password: string = process.env.REACT_APP_DEFAULT_LOGIN_PASSWORD || "";
constructor(props: ILoginPageProps) {
super(props);
this.state = {};
}
“官方”的做法是向构造函数添加 makeObservable
调用,并在那里设置注释。我已经设法手动重构了一个实际的类,并且它有效:
const LoginPage = observer(class LoginPageClass extends React.Component<ILoginPageProps,{}> {
private email: string = process.env.REACT_APP_DEFAULT_LOGIN_EMAIL || "";
private password: string = process.env.REACT_APP_DEFAULT_LOGIN_PASSWORD || "";
private catpchaKey: number = 0;
private catpchaToken: string | null = null;
private errormessage: string = "";
private overloaymessage: string = "";
private checking: boolean = false;
constructor(props: ILoginPageProps) {
super(props);
this.state = {};
makeObservable<LoginPageClass,"email"|"password"|"catpchaKey"|"catpchaToken"|"errormessage"|"overloaymessage"|"checking"|"loginEnabled"|"verifyCaptchaCallback">(this,{
email: observable,password: observable,catpchaKey: observable,catpchaToken: observable,errormessage: observable,overloaymessage: observable,checking: observable,loginEnabled: computed,verifyCaptchaCallback: action
})
}
get loginEnabled(): boolean {
return !!this.email && isValidEmail(this.email) && !!this.password && this.password.length > 4;
}
verifyCaptchaCallback = (token: string) => {
this.catpchaToken = token;
}
// More methods and code here...
}
export default LoginPage;
重构后的代码存在难以言喻的问题。仅举几例:
- 要生成类型安全代码,每个可观察属性的名称都必须键入 3 次。例如,名称“email”出现在字段声明中、makeObservable 调用的类型声明中以及 makeObservable 调用的 annotations 参数中。某些类最多可以包含一百个属性、计算属性和操作。
- 无法再使用标准重构工具重构此代码,因为字段名称出现在不相关的位置。没有任何 IDE 可以正确重构字段名称或 MobX 操作方法。
- 所有属性 getter 和 action 的名称必须一式三份,而且它们也不能轻易重构。
- 将方法标记为“绑定操作”的信息与方法定义分开。如果您快速查看一个方法定义,那么您将无法判断这是否是 MobX 操作。
- 与属性 getter 相同 - 它们可能会被计算,但您必须向上滚动到另一个地方才能找到。
他们建议的另一件事是使用 npx mobx-undecorate
- 但它不适用于 TypeScript。我试过了,它只是搞砸了我的代码。最终陷入了一个无限循环,耗尽了我所有的 cpu,打印了无尽的回溯等。最后它产生了如下代码:
export default const LoginPage = observer(class LoginPage extends React.Component<ILoginPageProps,{}> {
private email: string = process.env.REACT_APP_DEFAULT_LOGIN_EMAIL || "";
private password: string = process.env.REACT_APP_DEFAULT_LOGIN_PASSWORD || "";
constructor(props: ILoginPageProps) {
super(props);
makeObservable<LoginPage,"email" | "password">(this,});
this.state = {};
}
这太荒谬了,甚至不是有效的 TypeScript 代码。 (“导出默认常量”只是无效的语法。)它用函数调用替换了我的类,同时创建了一个名称冲突。函数名和类名相同。
据我所知,推荐的方法让一切变得更糟。
所以我最后的问题是:有没有一种方法可以将 React/MobX/TypeScript 代码从 MobX 5 重构到 MobX 6,而不会使代码变得一团糟?有没有人找到实现这一目标的方法?
解决方法
好吧,您似乎已经尝试了三种迁移方式中的第一种,但并不喜欢它。但这种方式只在以下情况下推荐:
如果您想在代码库中删除装饰器,并且项目还不太大,这是推荐的方法。
但我同意这种写 store 的方式对于 TS 来说确实很困难,很多重复等等。
如果您想继续使用装饰器,只需将它们保留在原处,并在构造函数中调用 makeObservable(this)
,就像文档说的那样:
留下所有装饰器并在构造函数中调用 makeObservable(this)。这将获取装饰器生成的元数据。如果您想限制 MobX 6 迁移的影响,这是推荐的方式。
还有第三种方式,我认为是目前最好的方式,没有任何膨胀:
移除装饰器并在类构造函数中使用 makeAutoObservable(this)。
我只是引用了您已经阅读过的文档,我不能建议任何其他迁移方式。如果你有装饰器的大项目,那么首先使用第二种方式,如果你喜欢,然后逐渐迁移到第三种方式。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。