Search code examples
typescriptvue.jsvuejs3vue-reactivity

In Vue 3, am I supposed to se the whole object structure when initializing a reactive value?


Suppose I want to create an empty value in my pinia store that hold the current subscription model the user is looking at. This should be null/unset if the user is not currently on a subscription detail page.

Flow: User clicks on the link to go to a subscription detail page of subscription ID 1. In the store, I'll dispatch an action to fetch the details of subscription id 1 and assign the object returned by my endpoint to that reactive variable.

export const useSubscriptionStore = defineStore("subscriptions", () => {
  let currentSubscription: Ref<SubscriptionModel> = reactive(null); // Null is not valid!

  async function loadSubscription(subscriptionId) {
    const { $api } = useNuxtApp();

    const { data } = await useAsyncData(() =>
      $api.subscriptions.getSubscription(subscriptionId),
    );
    currentSubscription.value = data.value;
  }

  return {
    loadSubscription,
  };
});

Am I supposed so set my reactive variable declared in line 2 to the same object structure I expect the backend to return? Isn't it possible to set a reactive variable that is capable both of holding the value null or an object?

In Vue 2, you were able to use Vue.set()


Solution

  • The correct type is SubscriptionModel | null, and it should be ref instead of reactive, especially since the type is already Ref. API functions are commonly generics in TypeScript, this allows to infer a type. Using const instead of let allows to avoid accidental reassignment, which is a common mistake resulting in loss of reactivity.

    It should be:

    const currentSubscription = ref<SubscriptionModel | null>(null);