#Is it possible to useState to change class bindings with ref across components?
20 messages · Page 1 of 1 (latest)
Sorry been stuck on this one for a few days. Can't seem to work it out >_<
More detail:
// components/ComponentA.vue
<template>
<div id="element"
:class="{open: openComponent}">
</div>
</template>
<script setup>
const openComponent = ref(false)
</script>
// components/Component.B.vue
<template>
<footer>
<button
@click="openComponentToggle">
</button>
</footer>
</template>
<script setup>
const openComponentToggle = useOpenComponentToggle();
</script>
// composables/states.js
export const useOpenComponentToggle = useState('openComponentToggle', () => openComponent.value = !openComponent.value);
This returns nuxt instance unavailable 😢
hi, you're getting nuxt instance unavailable because useOpenComponentToggle should be a function to ensure that the context is set when it is called.
// composables/states.js
export const useOpenComponentToggle = () => useState('openComponentToggle', () => openComponent.value = !openComponent.value);
Hey @magic current appreciate the reply. That makes sense and I've tried implementing that. However, there seems to be one more issue:
Now it's saying "openComponent is not defined", referring to the 'states.js' file
I guess it's not able to find the element to target? not sure what I'm missing...
openComponent is not reachable in your module. It's defined in a setup context.
Your composable should just define an initial value so the state can be set when initiated for the first time.
export const useOpenComponentToggle = () => useState('openComponentToggle', () => false)
In ComponentA.vue you'd then reference the state, which will be false by default:
<script setup>
const openComponent = useOpenComponentToggle()
</script>
In ComponentB.vue, you'd toggle the value as per usual:
<script setup>
const openComponentToggle = useOpenComponentToggle();
</script>
<template>
<button @click="openComponentToggle = !openComponentToggle" />
</template>
Or go one step further and congregate into a re-usable API:
const useOpenComponentToggleState = () => useState('openComponentToggle', () => false)
export const useOpenComponentToggle = () => {
const state = useOpenComponentToggleState()
const toggle = () => state.value = !state.value
return {
state,
toggle
}
}
and use it in ComponentA.vue as such:
<script setup>
const { state: isOpen } = useOpenComponentToggle()
</script>
<template>
<div id="element" :class="{ open: isOpen }" />
</template>
and in ComponentB.vue as such:
<script setup>
const { toggle } = useOpenComponentToggle()
</script>
<template>
<button @click="toggle" />
</template>
the world is your oyster.
Just working through this now. Appreciate it @delicate aurora !!
Just trying to get the first solution working before trying the re-usable API. The code runs but the class on the element doesn't seem to toggle
Does this look correct for ComponentA.vue:
<script setup>
const openComponent = useOpenComponentToggle();
</script>
<template>
<div id="element"
:class="{open: openComponent}">
</div>
</template>
Yep. Here's a repro https://stackblitz.com/edit/github-ye6fs6-cd1ysb?file=app.vue
Ohh nice. Ok going to cross-reference and make sure mine checks out. Thanks for this!
@delicate aurora My version of this isn't working. So strange because as far as I can tell it's structured the same https://codesandbox.io/s/pedantic-sea-207598
Any reason the repro is using an old version of Nuxt?
Hmm nope it was the first one I saw on codesandbox
Seems not to be working on my local server either, which should be up to date. But I’ll have to double check the version
Upgraded to 3.4.2 and it seems to work now. Thank you! @delicate aurora 🙏