vue.jsvue-componentvue-props

Provide and inject multiple properties and multiple functions that mutates multiple properties


According to the Vue documentation on provide and inject APIs https://vuejs.org/guide/components/provide-inject.html, you provide a state and function to update state like this:

<!-- inside provider component -->
<script setup>
import { provide, ref } from 'vue'

const location = ref('North Pole')

function updateLocation() {
  location.value = 'South Pole'
}

provide('location', {
  location,
  updateLocation
})
</script>

Here it supposes that you have one property and the function will only mutate this property, but what if I have multiple properties and functions that mutate multiple properties at once:

<script setup>
import Header from "@/Components/Header.vue";
import Nav from "@/Components/Nav.vue";
import { ref, provide } from "vue";

const isNavClosed = ref(false);
const isHamburgerClosed = ref(false);
const isScroll = ref(false);

function toggleNav() {
    isNavClosed.value = !isNavClosed.value;
    isHamburgerClosed.value = !isHamburgerClosed.value;
}

function enterLeaveNav() {
    if (isHamburgerClosed.value) {
        isNavClosed.value = !isNavClosed.value;
    }
    isScroll.value = !isScroll.value;
}


</script>

<template>
    <div>
        <!-- Page Heading -->
        <header class="header container">
            <Header />
        </header>
        <div class="container-fluid">
            <div class="row g-0">
                <nav
                    class="p-0 nav"
                    :class="[
                        isScroll ? 'overflowScroll' : 'overflowHidden',
                        isNavClosed ? 'width833' : 'width1633',
                    ]"
                    @mouseenter="enterLeaveNav"
                    @mouseleave="enterLeaveNav"
                >
                    <Nav />
                </nav>
                <main
                    class="ps-5"
                    :class="[
                        isNavClosed
                            ? 'offset-md-1 col-md-10'
                            : 'offset-md-2 col-md-9',
                    ]"
                    style="margin-top: 100px"
                >
                    <slot name="content" />
                </main>
            </div>
        </div>
    </div>
</template>

How can I provide all of these states and functions in one object, rather than providing every single property and function on its own, as all of them are related?


Solution

  • Here's your provide function that overrides the default vue provide. You could also not override, just rename, but I don't see much sense in keeping the default vue provide since the new function provides the same behavior:

    import {provide as vueProvide} from 'vue';
    export function provide(provides) {
        if (typeof provides === 'object') {
            for (const k in provides) {
                vueProvide(k, provides[k]);
            }
            return;
        }
        vueProvide(...arguments);
    }
    

    Usage:

    provide({
      location,
      updateLocation
    })