Reputation: 14705
We're using Vue 2 with the Vue Composition API and we're trying to create a composable that will expose application preferences:
// 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 }
}
This code works fine but when the composable is used in two components that are rendered at the same time we can see that watch
has been triggered twice. This is easily solved by moving the watch
function to the global scope (outside the function).
However, the issue then is that we can't use the darkModeMutation
. This graphql mutation can not be moved to the global scope outside of the function, if we do that the page doesn't even get rendered.
The goal is to have darkMode
available in many places and when the value of the darkMode
ref changes the mutation is only triggered once. How can this be achieved?
Upvotes: 0
Views: 1685
Reputation: 14705
Solved the issue by creating a callable function that starts watch
only when required (i.e. only once somewhere in the app).
// 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 }
}
Which the can be called once in MainLayout.vue
:
// MainLayout.vue
import { defineComponent } from '@vue/composition-api'
import { useApplicationPreferences } from 'useApplicationPreferences'
export default defineComponent({
setup() {
const { startWatch } = useApplicationPreferences()
startWatch()
},
})
All other components can then simply consume (get/set) the darkMode
ref as required while watch
is only running once.
// Settings.vue
import { defineComponent } from '@vue/composition-api'
import { useApplicationPreferences } from 'useApplicationPreferences'
export default defineComponent({
setup() {
const { darkMode } = useApplicationPreferences()
return { darkMode }
},
})
Upvotes: 2