如何创建一个将单个函数添加到组件类的装饰器?

时间:2018-01-24 17:57:15

标签: javascript reactjs decorator ecmascript-next

我应该通过说我对es7装饰器的了解很少来作为序言。基本上我想要的是一个名为@model的装饰器,它将一个函数添加到一个名为model的组件中。所以例如我称之为

@model class FooBar extends Component { }

然后FooBar类现在具有模型函数。

这是我试过的:

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 throws出现错误消息:

  

TypeError:超级表达式必须为null或函数,而不是对象

我不知道这意味着什么。我正在寻找一些帮助让我的装饰工作,并且奖励将是了解装饰器的概念。

2 个答案:

答案 0 :(得分:1)

您的模型装饰器不应返回新功能。 ctx将自动传递给modelDecorator。所以你真的需要从中返回新的扩展类:

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);
      }
    }
  }
}

答案 1 :(得分:1)

要添加到@ dfsq的答案(我假设它可以满足您的需求),您可以通过向{{1}添加.one-of-many-targets { ... } .one-of-many-targets__label { ... } .one-of-many-targets__feedback { ... } 来进一步提高界面性能。而不是像这样的每个实例:

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; } ,而不是附加prototype成员的范围副本每次构建新实例时,匿名扩展类model中的{1}}方法。

为了澄清,这意味着在@dfsq的答案中,每次构造新实例时都会调用model,而在此答案中,constructor仅在一次调用时被调用装饰器在课堂上被激活。

我在property descriptor中使用reactModelFactory()reactModelFactory()的原因是因为configurable语法本身定义writable上的成员方法}:



class { }