首页 > 解决方案 > 有什么办法可以同时使用 ES6 私有字段和 Vue 3 的 `reactive`?

问题描述

我有一个使用 ES6 私有字段和公共 getter 的类,我需要使用 Vue 3 的组合 API 进行反应。目前,我的设置如下所示:

//store.ts
class Store {
  #userName?: string
  get userName() {
    if(this.#userName !== undefined) return this.#userName
    throw new Error('Cannot get userName before it is defined')
  }

  setUserName(newUserName: string) {
    this.#userName = newUserName
  }
}

const store = reactive(new Store())

export { store }

然后通过提供/注入 API 将此存储实例提供给组件,并像这样使用

<template>
  <span> {{ formattedUserName }} </span>
</template>

<script lang="ts">
import { defineComponent, toRefs, inject } from 'vue'

export default defineComponent({
  setup(){
    const store = inject('storeKey')
    const formattedUserName = doSomeThings(store.userName)
    return { formattedUserName  }
})

但是当我尝试这样做时,我得到了这个错误: Cannot read private member #userName from an object whose class did not declare it

有人可以解释为什么会这样,如果有办法解决吗?我知道 TypeScript 有private关键字,但如果可能的话,我想使用私有字段,因为它们实际上在运行时强制执行隐私。

谢谢!

编辑:经过更多研究,我找到了问题“为什么”部分的答案。Vue 3 使用代理来跟踪反应性不幸的是它不适用于私有字段。如果有任何方法可以解决这个问题,我仍然很想知道。

标签: typescriptvue.jsvuejs3es6-classvue-composition-api

解决方案


如此简短的回答:没有简单的方法仍然可以同时使用私有字段和代理。现在(2021 年 8 月 10 日)实施的私有字段和代理从根本上不兼容。我原始帖子中的第二个链接对为什么会这样以及是否应该更改进行了大量讨论,但是如果没有新的提议,看起来事情就是这样。

这就是我如何建立一家商店的方法

  • 为其成员编译时间隐私
  • 那些保证返回值不是未定义的成员的反应性、只读(也在编译时)getter
  • 也可能有副作用的特定设置器
import {ref, reactive, computed} from 'vue'

class Store {
  private internal_userName: Ref<string | undefined> = ref(undefined)
  readonly userName = computed((): string => {
    if(this.internal_userName.value !== undefined) return this.internal_userName.value
    throw new Error('Cannot access userName before it is defined')
  })

  setUserName(newUserName: string) {
    // do side effects here, such as setting localStorage keys
    this.internal_userName.value = newUserName
  }
}

const store = reactive(new Store())

//do things to export or provide your store here

推荐阅读