Home > Back-end >  Using computed and composables in vue 3.2 with the setup script tag
Using computed and composables in vue 3.2 with the setup script tag

Time:01-01

I'm currently trying out some of the latest vue version and features (3.2).

I've created a useFetch composable to reuse some logic (it's based on the vue documentation)

useFetch.js

import { ref } from 'vue'
import axios from 'axios';

const apiClient = axios.create({
    baseURL: process.env.VUE_APP_API_ENDPOINT,
    withCredentials: false,
    headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
    },
    timeout: 10000,
});

export function useFetch(url) {
    const data = ref(null);
    const error = ref(null);
    const isLoading = ref(true);

    apiClient({ method, url, data: body })
        .then((response) => (data.value = response.data))
        .catch((err) => (error.value = err))
        .finally(() => isLoading.value = false)

  return { data, error }
}

I'm using the useFetch composable in a component to fetch companies from the backend. The data I'm getting back is rough so I want to reformat it using a computed (That was the way I did it when using vue 2)

CompanyList.vue

<script setup>
    import { computed } from 'vue';
    import useFetch from '@/composables/useFetch';
    import { formatEmail, formatPhone, formatEnterpriseNumber } from '@/utils/formatters';

    const { data, isLoading, error } = useFetch('get', '/companies');

    const companies = computed(() =>
        data.companies?.map((company) => ({
            id: `#${company.id}`,
            name: `${company.legal_entity_type} ${company.business_name}`,
            enterprise_number: formatEnterpriseNumber(company.enterprise_number),
            email: formatEmail(company.email),
            phone: formatPhone(company.phone),
        }))
    );
</script>

<template>
    <div v-if="isLoading">Loading...</div>
    <div v-else-if="error">Oops! Error encountered: {{ error }}</div>
    <div v-else-if="companies">
        Companies:
        <pre>{{ companies }}</pre>
    </div>
    <div v-else>No data :(</div>
</template>

When using Companies inside the template tags it stays null. I've checked and data has a companies property of the type Array with data in it.

Anyone an idea how to handle this?

CodePudding user response:

I think the issue may be due to use of ref. Try using reactive for data instead of ref

export function useFetch(url) {
    const data = reactive(null);
    const error = ref(null);
    const isLoading = ref(true);

    apiClient({ method, url, data: body })
        .then((response) => (data = response.data))
        .catch((err) => (error.value = err))
        .finally(() => isLoading.value = false)

  return { data, error }
}

To use ref, you would need to access the value via ref.value. Also, ref is not the best choice for objects and arrays as it was meant for primitive data types. to use ref you can

const companies = computed(() =>
  data.value?.companies?.map((company) => ({
    id: `#${company.id}`,
    name: `${company.legal_entity_type} ${company.business_name}`,
    enterprise_number: formatEnterpriseNumber(company.enterprise_number),
    email: formatEmail(company.email),
    phone: formatPhone(company.phone),
  }))
);

note the use of ?. after value, which is required since the ref is null initially.

  • Related