【问题标题】:An element descriptor's .kind property must be either "method" or "field"元素描述符的 .kind 属性必须是“方法”或“字段”
【发布时间】:2019-03-08 18:04:24
【问题描述】:

我正在关注mobx-react-router 的文档,但在尝试运行我的应用程序时,我在浏览器中收到以下错误:

Uncaught TypeError: An element descriptor's .kind property must be either "method" or "field", but a decorator created an element descriptor with .kind "undefined"
    at _toElementDescriptor (app.js:49988)
    at _toElementFinisherExtras (app.js:49990)
    at _decorateElement (app.js:49980)
    at app.js:49976
    at Array.forEach (<anonymous>)
    at _decorateClass (app.js:49976)
    at _decorate (app.js:49958)
    at Module../src/App/UserStore.js (app.js:50012)
    at __webpack_require__ (bootstrap:19)
    at Module../src/index.js (index.js:1)

我是这样初始化的:

const appContainer = document.getElementById('app');
if(appContainer) {
  const browserHistory = createBrowserHistory()
  const routingStore = new RouterStore();

  const stores = {
    users: userStore,
    routing: routingStore
  }

  const history = syncHistoryWithStore(browserHistory, routingStore);

  ReactDOM.render(
    (
      <Provider {...stores}>
        <Router history={history}>
          < App />
        </Router>
      </Provider>
    ),
  appContainer);
}

这就是我的使用方式:

@inject('routing')
@inject('users')
@observer
class App extends Component { ...

我的UserStore

import { observable, action, computed } from "mobx"

class UserStore {
  @observable users = [];

  @action addUser = (user) => {
    this.users.push(user)
  }

  @computed get userCount () {
    return this.users.length
  }
}

const store = new UserStore();
export default store;

我已尝试通过 Google 搜索此错误,但它没有返回任何有用的结果。任何想法我做错了什么?

【问题讨论】:

    标签: mobx mobx-react


    【解决方案1】:

    如果你使用 Babel 7 安装对装饰器的支持:

    npm i -D\
      @babel/plugin-proposal-class-properties\
      @babel/plugin-proposal-decorators
    

    然后在您的.babelrcwebpack.config.js 文件中启用它:

    {
        "plugins": [
            ["@babel/plugin-proposal-decorators", { "legacy": true}],
            ["@babel/plugin-proposal-class-properties", { "loose": true}]
        ]
    }
    

    请注意,遗留模式很重要(就像将装饰器提案放在首位一样)。非传统模式是WIP

    参考:https://mobx.js.org/best/decorators.html

    【讨论】:

      【解决方案2】:

      虽然接受的答案有效,但对于来自相同错误消息但不同上下文的任何人来说,这可能是因为装饰器的签名随着the proposal 的进展而改变。

      使用{ "legacy": true } 使用一个方法签名,而{"decoratorsBeforeExport": true } 使用另一个。这两个标志不兼容。

      您可以检查给定示例的情况

      function log() {
        console.log(arguments)
      }
      class Foo
        @log
        bar() {
          console.log('hello')
        }
      }
      new Foo().bar()
      

      使用{"decoratorsBeforeExport": true } 将产生

      [Arguments] {
        '0': Object [Descriptor] {
          kind: 'method',
          key: 'bar',
          placement: 'prototype',
          descriptor: {
            value: [Function: bar],
            writable: true,
            configurable: true,
            enumerable: false
          }
        }
      }
      

      {"legacy": true } 会给你哪里

      [Arguments] {
        '0': Foo {},
        '1': 'bar',
        '2': {
          value: [Function: bar],
          writable: true,
          enumerable: false,
          configurable: true
        }
      }
      

      使用遗留语义,编写装饰器相当简单。返回其第 0 个参数的装饰器是无操作的。您也可以在返回之前进行变异。使用新语义,您可以如下描述装饰器:

      function log(obj) {
        console.log('I am called once, when the decorator is set')
        let fn = obj.descriptor.value
        obj.descriptor.value = function() {
          console.log('before invoke')
          fn()
          console.log('after invoke')
        }
        return obj
      }
      

      【讨论】:

      • 我觉得这应该是公认的答案。谢谢你。但是,这是否意味着 babel 插件完全脱离了最新规范?我看到 api 应该有 2 个参数值和上下文。此外,上下文对象看起来完全不同!
      • babel 插件是在提案成熟之前添加的。 (您可以在此处阅读更多关于该提案的信息 -> github.com/tc39/proposal-decorators)由于规范发生了变化,babel 插件选择同时支持新旧版本,而不是分叉。它支持 { "legacy": true } 规范的旧签名和原始版本。它还支持 {"decoratorsBeforeExport": true } 规范的新签名和当前版本。
      • 非常感谢。这确实应该是公认的答案。
      【解决方案3】:

      我像这样更改了 observable 并且它可以工作(虽然不确定为什么):

      import { observable, action, computed } from "mobx"
      
      class UserStore {
        @observable users;
      
        constructor() {
          this.users = []
        }
      
        @action addUser = (user) => {
          this.users.push(user)
        }
      }
      
      const store = new UserStore();
      export default store;
      

      【讨论】:

      • 能否分享一下 package.josn 和 .babelrc 的内容。面对上述类似问题不起作用。
      猜你喜欢
      • 2022-01-15
      • 2021-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多