posva / unplugin-vue-router

Next Generation file based typed routing for Vue Router
https://uvr.esm.is
MIT License
1.69k stars 82 forks source link

Data Loader does not reload data when only used outside of page component #535

Open ricktibbe opened 2 weeks ago

ricktibbe commented 2 weeks ago

I don't know if this is expected behavior, but according to the docs, it should be possible to use a Data Loader outside page components. However, doing so seems to break the Smart Refreshing feature as described in the RFC, as the data does not get reloaded when navigating to another page when the Data Loader is not used in any page component. Adding the Data Loader's import/export to the page component, and then using it in non-page components seems to be the current workaround.


I've got the following Data Loader:

import { defineBasicLoader } from 'unplugin-vue-router/data-loaders/basic';
import { ApiSdk } from '@my-project/api-sdk';

const api = new ApiSdk();

const getCustomerOrders = async (customerId: string) => {
  const response = await api.customers.orders(customerId);

  if (response.status !== 'success') return [];

  return response.data;
};

export const useCustomerOrders = defineBasicLoader(
  '/customers/[customerId]',
  async (route) => getCustomerOrders(route.params.customerId),
);

The Data Loader is used like this in my <OrdersList> component (simplified example), which is then used in my page component for the /customer/[customerId] route (/customers/[customerId]/index.vue):

<script lang="ts">
import { useCustomerOrders } from '../../Loaders/customerOrders';
export { useCustomerOrders };
</script>

<script setup lang="ts">
const { data: orders } = useCustomerOrders();
</script>

<template>
  <List>
    <Order v-for="order in orders" :key="order.id" :order />
  </List>
</template>

When I navigate for the first time to the /customer/[customerId] page (with customerId = C0001), the orders for customer C0001 will load properly. However, when I then navigate to /customer/C0002, it'll still display the orders from customer C0001, and the networking tab of the DevTools also doesn't show a new request to the /orders endpoint of the API. When doing a hard refresh of the page (Cmd + R), while on /customer/C0002, it'll now fetch the orders from C0002, but not the orders of C0001 when navigating to that page again.

In the situation above, the Loader is only added to the OrdersList component, which is then used on the /customers/[customerId] page (file-based routing). While this does not reload the data on subsequent navigation, the problem does seem to get fixed by adding the Loader's import/export to the specific page file where the component is used. So, for example, by adding this to the /customers/[customerId]/index.vue page component:

<script lang="ts">
import { useCustomerOrders } from '../../Loaders/customerOrders';
export { useCustomerOrders };
</script>

the <OrdersList> component on that page will now have the proper data that gets reloaded when navigating to another [customerId].

posva commented 2 weeks ago

Can you put up a repro please?

posva commented 2 weeks ago

I misread: the data loaders has to be exported from the page component. Exporting it from any other component has no effect and can be safely removed. So this is indeed working as expected.

posva commented 2 weeks ago

I think we could add the name of the file to https://uvr.esm.is/data-loaders/#quick-start where this is mentioned to make it more explicit. @ricktibbe If you want you can send a PR. Otherwise I will add it later on

ricktibbe commented 2 weeks ago

@posva I've opened a PR with an addition to the quick-start section, and the 'Organizing Loaders' > 'Usage outside of page components' section a well. It's minimal, but should be clear enough I think