javascriptvue.jsvuejs3hierarchyslots

How to use scoped slot prop in parent computed


I have a thightly coupled duo of parent-child components using a scoped slot. In the parent, some data is received from the child via the scoped slot prop (let's call it myScopedProp). All is well with all of this. In the parent's scoped slot, I can pass myScopedProp as an argument to some methods in the parent script, that works.

Now how can I access this myScopedProp in a computed function present in the parent whithout first setting it as data? Is there a built in vuejs way to access myScopedProp from the parent script?

<!-- parent -->
<template>
  <child>
    <template #theSlot="{ myScopedProp}">
      {{ parentMethod(myScopedProp) }} <-- this works fine
    </template>
  </child>
</template>

<!-- child -->
<template>
  <slot name="theSlot" :myScopedProp="someChildValue">
</slot>
</template>

I presently hack this by passing to the child a method from the parent which sets the myScopedProp value in the parent's data, but that feels wrong and redundant since I already have this value passed via the scoped slot.


Solution

  • VUE SFC PLAYGROUND

    There's many options how to do this, I would use provide/inject since the components are tightly bound. It's called lifting state. Even v-model would work.

    Another options:

    1. assign the value directly like you tried with a function
    2. and I guess the most idiomatic is to use defineExpose() macro and a component ref:
    <script setup>
    import { ref, provide, cloneVNode } from 'vue';
    import Comp from './Comp.vue';
    
    const slotProp = ref();
    const $comp = ref();
    const providedProp = ref();
    provide('providedProp', providedProp);
    
    </script>
    
    <template>
      <h1>{{ slotProp }}</h1>
      <h1>{{ $comp?.prop }}</h1>
      <h1>{{ providedProp }}</h1>
      <comp ref="$comp" #="{prop}" v-assign="comp => directiveProp = comp.internal">{{ (slotProp = prop, '') }}</comp>
    </template>
    

    Comp.vue:

    <script setup>
    import {ref, inject} from 'vue';
    const prop = ref('Slot prop');
    const exposed = ref('Exposed prop');
    defineExpose({prop: exposed});
    const provided = inject('providedProp');
    provided.value = 'Provided prop';
    
    const changeProps = () => {
      [prop, exposed, provided].forEach(r => r.value += ' changed')
    };
    </script>
    
    <template>
      <div>
        <slot v-bind="{prop}"/>
        <div>
          <button @click="changeProps">Change props</button>
        </div>
      </div>
      
    </template>