如何创建一个给组件添加单个函数的装饰器class?
How to create a decorator that adds a single function to the component class?
我应该先说我对 es7 装饰器知之甚少。基本上我想要的是一个名为 @model
的装饰器,它将一个函数添加到一个名为 model
的组件中。例如,我会称它为
@model class FooBar extends Component { }
然后 FooBar class 现在将具有模型功能。
这是我尝试过的:
Model.js
export default function reactModelFactory( ctx ){
return (key)=>{
return {
onChange: (e)=>ctx.setState({[key]:e.target.value}),
value: ctx.state[key],
name: key
};
};
};
function modelDecorator() {
return function(ctx){
return class extends ctx{
constructor(...args){
super(...args);
this.model = reactModelFactory(this);
}
}
}
}
export { modelDecorator as model };
Login.js
import React,{PureComponent} from 'react';
import {model} from './Model';
@model class Login extends PureComponent{}
React 抛出错误消息:
TypeError: Super expression must either be null or a function, not object
我不知道这是什么意思。我正在寻求一些帮助来让我的装饰器正常工作,而额外的好处就是完全理解装饰器的概念。
您的模型装饰器不应 return 新函数。 ctx
将传递给 modelDecorator
本身。所以你真的只需要 return 从它新扩展 class:
function modelDecorator(ctx) {
return class extends ctx {
constructor(...args) {
super(...args);
this.model = reactModelFactory(this);
}
}
}
请注意,如果您的装饰器应该像这样使用(Angular 样式装饰器),您尝试的语法将起作用:
@model({ modelName: 'user' })
class Login extends PureComponent {}
那么您将需要额外的闭包来将传递的参数保存到您的装饰器中:
function modelDecorator({ modelName }) {
return (ctx) => {
console.log('model name', modelName)
return class extends ctx {
constructor(...args) {
super(...args);
this.model = reactModelFactory(this);
}
}
}
}
要添加到@dfsq 的答案(我假设它可以满足您的要求),您可以通过将 model()
添加到 prototype
而不是在界面性能方面更进一步对于这样的每个实例:
export default function reactModelFactory() {
return function model (key) {
return {
onChange: (e) => this.setState({ [key]: e.target.value }),
value: this.state[key],
name: key
};
};
};
function modelDecorator(Class) {
Object.defineProperty(Class.prototype, 'model', {
value: reactModelFactory(),
configurable: true,
writable: true
});
return Class;
}
这对于性能来说要好得多,因为它会导致装饰器使用 model
成员方法一次性修改现有的 class 的 prototype
,而不是附加一个作用域每次构造新实例时,匿名扩展 class 的 constructor
中 model
方法的副本。
澄清一下,这意味着在@dfsq 的回答中,每次构造新实例时都会调用 reactModelFactory()
,而在这个回答中,reactModelFactory()
仅在装饰器时被调用一次在 class.
上激活
我在 property descriptor 中使用 configurable
和 writable
的原因是因为这就是 class { }
语法在 prototype
上本地定义成员方法的方式:
class Dummy {
dummy () {}
}
let {
configurable,
writable,
enumerable
} = Object.getOwnPropertyDescriptor(Dummy.prototype, 'dummy');
console.log('configurable', configurable);
console.log('enumerable', enumerable);
console.log('writable', writable);
我应该先说我对 es7 装饰器知之甚少。基本上我想要的是一个名为 @model
的装饰器,它将一个函数添加到一个名为 model
的组件中。例如,我会称它为
@model class FooBar extends Component { }
然后 FooBar class 现在将具有模型功能。
这是我尝试过的:
Model.js
export default function reactModelFactory( ctx ){
return (key)=>{
return {
onChange: (e)=>ctx.setState({[key]:e.target.value}),
value: ctx.state[key],
name: key
};
};
};
function modelDecorator() {
return function(ctx){
return class extends ctx{
constructor(...args){
super(...args);
this.model = reactModelFactory(this);
}
}
}
}
export { modelDecorator as model };
Login.js
import React,{PureComponent} from 'react';
import {model} from './Model';
@model class Login extends PureComponent{}
React 抛出错误消息:
TypeError: Super expression must either be null or a function, not object
我不知道这是什么意思。我正在寻求一些帮助来让我的装饰器正常工作,而额外的好处就是完全理解装饰器的概念。
您的模型装饰器不应 return 新函数。 ctx
将传递给 modelDecorator
本身。所以你真的只需要 return 从它新扩展 class:
function modelDecorator(ctx) {
return class extends ctx {
constructor(...args) {
super(...args);
this.model = reactModelFactory(this);
}
}
}
请注意,如果您的装饰器应该像这样使用(Angular 样式装饰器),您尝试的语法将起作用:
@model({ modelName: 'user' })
class Login extends PureComponent {}
那么您将需要额外的闭包来将传递的参数保存到您的装饰器中:
function modelDecorator({ modelName }) {
return (ctx) => {
console.log('model name', modelName)
return class extends ctx {
constructor(...args) {
super(...args);
this.model = reactModelFactory(this);
}
}
}
}
要添加到@dfsq 的答案(我假设它可以满足您的要求),您可以通过将 model()
添加到 prototype
而不是在界面性能方面更进一步对于这样的每个实例:
export default function reactModelFactory() {
return function model (key) {
return {
onChange: (e) => this.setState({ [key]: e.target.value }),
value: this.state[key],
name: key
};
};
};
function modelDecorator(Class) {
Object.defineProperty(Class.prototype, 'model', {
value: reactModelFactory(),
configurable: true,
writable: true
});
return Class;
}
这对于性能来说要好得多,因为它会导致装饰器使用 model
成员方法一次性修改现有的 class 的 prototype
,而不是附加一个作用域每次构造新实例时,匿名扩展 class 的 constructor
中 model
方法的副本。
澄清一下,这意味着在@dfsq 的回答中,每次构造新实例时都会调用 reactModelFactory()
,而在这个回答中,reactModelFactory()
仅在装饰器时被调用一次在 class.
我在 property descriptor 中使用 configurable
和 writable
的原因是因为这就是 class { }
语法在 prototype
上本地定义成员方法的方式:
class Dummy {
dummy () {}
}
let {
configurable,
writable,
enumerable
} = Object.getOwnPropertyDescriptor(Dummy.prototype, 'dummy');
console.log('configurable', configurable);
console.log('enumerable', enumerable);
console.log('writable', writable);