Home > Software engineering >  How to destructure object props in Vue the way like you would do in React inside a setup?
How to destructure object props in Vue the way like you would do in React inside a setup?

Time:04-15

I am wondering how to destructure an object prop without having to type data.title, data.keywords, data.image etc. I've tried spreading the object directly, but inside the template it is undefined if I do that.

Would like to return directly {{ title }}, {{ textarea }} etc.

My code:

   <template>
      <div>
        <h1>{{ title }}</h1>
      </div>
    </template>
    
    <script lang="ts">
    import { useSanityFetcher } from "vue-sanity";
    import { defineComponent, reactive, toRefs } from "vue";
    
    export default defineComponent({
      name: "App",
      setup: () => {
        const articleQuery = `*[_type == "article"][0] {
            title,
            textarea,
        }`;
    
        const options = {
          listen: true,
          clientOnly: true,
        };
    
        const res = useSanityFetcher<any | object>(articleQuery, options);
        const data = reactive(res.data);
    
        return toRefs(data);
      },
    });
    </script>

CodePudding user response:

The Vue docs actually recommend not destructing props because of the way reactivity works but if you really want to something like this should work:

const res = useSanityFetcher<any | object(articleQuery, options);
const data = reactive(res.data);

return toRefs(data);

Don't forget to import reactive and toRefs.

CodePudding user response:

Considering that useSanityFetcher is asynchronous, and res is reactive, it's incorrect to access res.data directly in setup because this disables the reactivity. Everything should happen in computed, watch, etc callback functions.

title, etc properties need to be explicitly listed in order to map reactive object to separate refs with respective names - can probably be combined with articleQuery definition or instantly available as res.data keys

E.g.:

const dataRefs = Object.fromEntries(['title', ...].map(key => [key, ref(null)]))

const res = ...

watchEffect(() => {
  if (!res.data) return;
  for (const key in dataRefs)
    dataRefs[key] = res.data[key];
});

return { ...dataRefs };

CodePudding user response:

Destructuring the object is not the problem, see Vue SFC Playground

<script lang="ts">
//import { useSanityFetcher } from "vue-sanity";
import { defineComponent, reactive, toRefs } from "vue";

export default defineComponent({
  name: "App",
  setup: () => {
    const res = {
      data: {
        title: 'Hi there'
      }
    }
    const data = reactive(res.data);

    return toRefs(data);
  },
});
</script>

<template>
  <div>
    <h1>{{ title }}</h1>
  </div>
</template>

It may simply be the space between the filter and the projection in the GROQ expression

const articleQuery = `*[_type == "article"][0]{ title, textarea }`;

See A description of the GROQ syntax

A typical GROQ query has this form:

*[ <filter> ]{ <projection> }

  • Related