【问题标题】:Vue composable scoping issueVue可组合范围问题
【发布时间】:2021-03-16 07:30:21
【问题描述】:

我们将 Vue 2 与 Vue 组合 API 一起使用,并且我们正在尝试创建一个可组合来公开应用程序首选项:

// useApplicationPreferences.ts
import { ref, watch } from '@vue/composition-api'
import { useSetDarkModeMutation, useViewerQuery } from 'src/graphql/generated/operations'

const darkMode = ref(false) // global scope

export const useApplicationPreferences = () => {
  const { mutate: darkModeMutation } = useSetDarkModeMutation(() => ({
    variables: {
      darkMode: darkMode.value,
    },
  }))

  watch(darkMode, async (newDarkMode) => {
    console.log('darkMode: ', newDarkMode)
    await darkModeMutation()
  })

  return { darkMode }
}

这段代码工作正常,但是当可组合用于同时渲染的两个组件中时,我们可以看到watch 已被触发两次。这很容易通过将watch 函数移动到全局范围(函数外)来解决。

但是,问题是我们不能使用darkModeMutation。这个 graphql 突变不能移动到函数之外的全局范围,如果我们这样做,页面甚至不会被渲染。

我们的目标是让darkMode 在许多地方都可用,并且当darkMode ref 的值发生变化时,突变只会触发一次。如何实现?

【问题讨论】:

  • 导出darkMode 并在某处调用一次useApplicationPreferences 怎么样?或者,既然 ref 应该是一个单例,不妨从根组件向下传递,并将其用作此可组合函数的参数。
  • 使用可组合函数的整个想法是能够在许多地方重用它。附带说明一下,有许多 ref 对象,而不仅仅是示例中的一个。
  • 是的,明白了。但是像那些分散在不同地方的单身人士(而不是集中的来源),随着规模的扩大,维护起来会变得更加困难。此外,我在这个函数中看不到任何应该是可组合的——重复的手表告诉你这不是正确的模式。
  • 我明白了。但是我们需要在MainLayout.vueSettings.vue 中加载应用偏好。我们甚至可能有一个Statusbar.vue,我们需要相同的ref,比如DarkModelanguage,......集中组合似乎是个好主意。
  • 我仍然更喜欢 dependency injection 对于这个特定的用例。 Vuetify 内部似乎也使用了几乎相同的方法。

标签: vue.js vuejs2 vue-component vue-composition-api


【解决方案1】:

通过创建一个可调用函数解决了这个问题,该函数仅在需要时启动 watch(即仅在应用程序的某个位置启动一次)。

// useApplicationPreferences.ts
import { ref, watch } from '@vue/composition-api'
import { useSetDarkModeMutation, useViewerQuery } from 'src/graphql/generated/operations'

const darkMode = ref(false) // global scope

export const useApplicationPreferences = () => {
  const { mutate: darkModeMutation } = useSetDarkModeMutation(() => ({
    variables: {
      darkMode: darkMode.value,
    },
  }))

  const startWatch = () => {
    watch(darkMode, async (newDarkMode) => {
      await darkModeMutation()
    })
  }
  return { darkMode, startWatch }
}

MainLayout.vue中可以调用一次:

// MainLayout.vue
import { defineComponent } from '@vue/composition-api'
import { useApplicationPreferences } from 'useApplicationPreferences'

export default defineComponent({
  setup() {
    const { startWatch } = useApplicationPreferences()
    startWatch()
  },
})

所有其他组件然后可以根据需要简单地使用(获取/设置)darkMode 引用,而 watch 只运行一次。

// Settings.vue
import { defineComponent } from '@vue/composition-api'
import { useApplicationPreferences } from 'useApplicationPreferences'

export default defineComponent({
  setup() {
    const { darkMode } = useApplicationPreferences()

    return { darkMode }
  },
})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    • 2013-02-25
    • 1970-01-01
    • 1970-01-01
    • 2013-05-18
    • 2018-11-09
    • 1970-01-01
    相关资源
    最近更新 更多