Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Multiple composable instances within a single script tag in Vue 3

I’m currently undertaking a rewrite of our components that are currently written with the Options API. One interesting point for a rewrite from a code-cut standpoint is our many modals, which all have their own closing/opening and boolean logic attached everywhere they’re present.

My issue is that I’m having a hard time figuring out how to get a composable function to work for more than 1 instance of a modal.

Take this extremely simple example:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Modal.vue

<template>
  <div v-if="isOpen" @click="$emit('closeModal')"> 
    <slot></slot>
  </div>
</template>
const props = defineProps<{ isOpen: false }>();

useModal.ts

export default const useModal = () => {
  const isModalOpen = ref(false);
  const toggleModal = () => isModalOpen.value = !isModalOpen.value;

  return { isModalOpen, toggleModal }
}

And to use this in a component somewhere, you’d do something like this

Component.vue

<template>
  <button @click="toggleModal">Open modal<button>
  <Modal :is-open="isModalOpen" @close-modal="toggleModal">Modal Content</Modal>
</template>
import useModal from "useModal";

const { isModalOpen, toggleModal } = useModal();

This works just fine when it’s just one Modal on the page, but how can I get this to properly work with any arbitrary number of Modals on the page? Obviously I’d still need to define the variable name to keep track of which modal gets toggled/is opened, but how do I do this without basically just recreating the content of the useModal composition for each and every modal on the page?

Ideally I’d want to do something similar to this

<template>
  <button @click="toggleOne">Open 1</button>
  <button @click="toggleTwo">Open 2</button>

  <Modal :is-open="isOneOpen" @close-modal="toggleOne">Modal 1</Modal>
  <Modal :is-open="isTwoOpen" @close-modal="toggleTwo">Modal 2</Modal>
</template>
import useModal from "useModal";

const { isOneOpen, toggleOne } = useModal();
const { isTwoOpen, toggleTwo } = useModal();

But this doesn’t work (somewhat obviously). Is there a way for me to achieve what I’m aiming for here, or am I fundamentally misunderstanding how/when to use composables?

I’ve tried some varieties like this

const { isModalOpen as isOneOpen } = useModal();

const isOneOpen = useModal().isModalOpen;

const isOneOpen = { ...useModal().isModalOpen; };

But none of these worked for me.

>Solution :

You can reassign the names of the composable’s return values during the object destructure like this:

const { isModalOpen: modalOne, toggleModal: toggleModalOne } = useModal();

That should be enough to differentiate which modal’s state to track.

Working example here: https://codesandbox.io/s/vue-3-composition-destructuring-fts2x9

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading