javascriptvue.jsvuejs3

Template doesn't update with ref()


I have a component which needs some external data (API) to fill some content in the template through asynchronous functions. I reduced it the more I could and renamed some variables for better understanding.

The component:

<template>
  <div>
    <h3>Scheduled Events</h3>
    <div v-if="error">{{ error }}</div>
    <div v-if="nextEvent">
      <h1>{{ nextEvent.event.name }}</h1>
      <p>test</p>
    </div>
  </div>
</template>

<script>
export default {
  components: { EventSnippet },
  setup() {
    const { error, getNextEvents, getNextEventDetails } = useSchedule(2025);
    const { nextEvent } = getNextEventDetails();

    return { error, nextEvent };
  },
};
</script>

and the composable:

import { ref } from "vue";
import callApi from "./API/callAPI";

const useSchedule = (year) => {
  const error = ref(null);

  const getSchedule = async () => {
    const query = {
      request: "getEventId",
      params: { year: year, league: "xyz" },
    };
    const res = await callApi(query);
    return res;
  };

  const getNextEvents = async () => {
    const nextEvents = ref(null);
    const yearSchedule = await getSchedule();
    const onlyFutureEvents = yearSchedule.result.filter((event) => {
      return new Date(event.startDate).getTime() > new Date().getTime();
    });
    const arrayNextSorted = onlyFutureEvents.sort(
      (event, today = new Date()) => {
        const eventDate = new Date(event.date);
        console.log(eventDate - today);
        return eventDate - today;
      }
    );
    nextEvents.value = arrayNextSorted;
    return nextEvents;
  };

  const getNextEventDetails = async () => {
    const nextEvent = ref(null);
    try {
      const nextEvents = await getNextEvents();

      const nextEventid = nextEvents.value[0].eventId;
      const query = {
        request: "getEventDetails",
        params: { league: "xyz", eventId: nextEventid },
      };
      const res = await callApi(query);
      nextEvent.value = res;
    } catch (err) {
      error.value = err.message;
    }
    return { nextEvent };
  };

  return { error, getNextEvents, getNextEventDetails };
};

export default useSchedule;

I'll quickly explain why I tried with this composable solution:

I don't pretend this is an OK code, probably ill-written, it's just the best I could do based on my little experience.

Now, whenever I console log the values through the composable, they are all correct. I feel like I lost myself with all the async/await maybe and for sure with ref() reactivity, too.


Solution

  • Try to separate the state from the inner functions and hoist them in the main composable function; then just destruct the composable with functions and state :

    import { ref } from "vue";
    import callApi from "./API/callAPI";
    
    const useSchedule = (year) => {
      const error = ref(null);
    
     const nextEvents = ref([]);
     const nextEvent = ref(null);
    
      const getSchedule = async () => {
        const query = {
          request: "getEventId",
          params: { year: year, league: "xyz" },
        };
        const res = await callApi(query);
        return res;
      };
    
      const getNextEvents = async () => {
       
        const yearSchedule = await getSchedule();
        const onlyFutureEvents = yearSchedule.result.filter((event) => {
          return new Date(event.startDate).getTime() > new Date().getTime();
        });
        const arrayNextSorted = onlyFutureEvents.sort(
          (event, today = new Date()) => {
            const eventDate = new Date(event.date);
            console.log(eventDate - today);
            return eventDate - today;
          }
        );
        nextEvents.value = arrayNextSorted;
       
      };
    
      const getNextEventDetails = async () => {
        
        try {
          const nextEvents = await getNextEvents();
    
          const nextEventid = nextEvents.value[0].eventId;
          const query = {
            request: "getEventDetails",
            params: { league: "xyz", eventId: nextEventid },
          };
          const res = await callApi(query);
          nextEvent.value = res;
        } catch (err) {
          error.value = err.message;
        }
    
      };
    
      return { error, getNextEvents, getNextEventDetails, nextEvent , nextEvents };
    };
    
    export default useSchedule;
    

    then use the composable as follows :

    <script>
    export default {
      components: { EventSnippet },
     setup() {
        const { error, getNextEvents, getNextEventDetails, nextEvent } = useSchedule(2025);
         // call the function that mutates the state
        getNextCardDetails();
    
        return { error, nextEvent };
      },
    };
    </script>