defineColadaLoader
This commit is contained in:
76
src/pages/data-loaders.[id]/index.page.vue
Normal file
76
src/pages/data-loaders.[id]/index.page.vue
Normal file
@ -0,0 +1,76 @@
|
||||
<script lang="ts">
|
||||
import { defineBasicLoader } from 'unplugin-vue-router/data-loaders/basic';
|
||||
// https://uvr.esm.is/data-loaders/rfc.html
|
||||
|
||||
export const usePageData = defineBasicLoader(
|
||||
'DataLoadersId',
|
||||
async (route, ...otherArgs) => {
|
||||
console.log('[DefineLoaderFn]', 'otherArgs :>> ', otherArgs);
|
||||
await new Promise((resolve) => setTimeout(resolve, 777));
|
||||
return { idFromPreviousPage: route.params.id, someOtherData: 'someOtherData' };
|
||||
},
|
||||
{
|
||||
lazy: false,
|
||||
commit: 'immediate',
|
||||
// - `immediate`: the data is committed as soon as it is loaded.
|
||||
// - `after-load`: the data is committed after all non-lazy loaders have finished loading.
|
||||
// - `immediate`:数据在加载后立即提交。
|
||||
// - `after-load`:数据在所有非惰性加载器加载完成后提交。
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
meta: {
|
||||
metaKey: 'metaValue',
|
||||
},
|
||||
});
|
||||
const {
|
||||
data: pageData, // the data returned by the loader
|
||||
isLoading, // a boolean indicating if the loader is fetching data
|
||||
error, // an error object if the loader failed
|
||||
reload, // a function to refetch the data without navigating
|
||||
} = usePageData();
|
||||
|
||||
const route = useRoute('DataLoadersId');
|
||||
|
||||
watch(
|
||||
pageData,
|
||||
(pageDataVal) => {
|
||||
const message = [`[watch]`, `pageDataVal :>> `, pageDataVal];
|
||||
if (pageDataVal === undefined) {
|
||||
// hot updated 会造成 pageDataVal 为 undefined
|
||||
console.warn(message);
|
||||
} else {
|
||||
console.debug(message);
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>Data Loaders</h1>
|
||||
<ul>
|
||||
<li>
|
||||
<RouterLink class="green" :to="{ name: 'DataLoadersIdSub1UserId', params: { id: route.params.id, userId: '1' } }"
|
||||
>sub-1</RouterLink
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<div flex="~ row">
|
||||
<button class="green" @click="$router.back()">Back</button>
|
||||
<button class="green" @click="reload()">Reload</button>
|
||||
</div>
|
||||
<main>
|
||||
<p v-if="isLoading">Loading...</p>
|
||||
<template v-else-if="error">
|
||||
<p>{{ error.message }}</p>
|
||||
<button class="green" @click="reload()">Retry</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p>{{ pageData }}</p>
|
||||
</template>
|
||||
</main>
|
||||
</template>
|
141
src/pages/data-loaders.[id]/sub-1.[userId].page.vue
Normal file
141
src/pages/data-loaders.[id]/sub-1.[userId].page.vue
Normal file
@ -0,0 +1,141 @@
|
||||
<script lang="ts">
|
||||
import { defineColadaLoader } from 'unplugin-vue-router/data-loaders/pinia-colada';
|
||||
|
||||
async function getUserById(id: string, { signal }: { signal?: AbortSignal }) {
|
||||
console.warn('[getUserById] 被调用, id :>> ', id);
|
||||
setTimeout(() => {
|
||||
console.log('5s 已过', 'id :>> ', id);
|
||||
}, 5000);
|
||||
const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`, { signal });
|
||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
export const useUserData = defineColadaLoader('DataLoadersIdSub1UserId', {
|
||||
async query(to, { signal }) {
|
||||
console.debug('[defineColadaLoader] query');
|
||||
return getUserById(to.params.userId, { signal });
|
||||
},
|
||||
key: (to) => ['users', to.params.userId],
|
||||
// Keep the data "fresh" 10 seconds to avoid fetching the same data too often
|
||||
// 保持数据“新鲜”10秒,以避免过于频繁地获取相同的数据
|
||||
staleTime: 5000,
|
||||
});
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { data: user, status, error, isLoading, reload, refresh } = useUserData();
|
||||
|
||||
const route = useRoute('DataLoadersIdSub1UserId');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div flex="~ row">
|
||||
<button class="green" @click="$router.back()">Back</button>
|
||||
</div>
|
||||
<h1>Pinia Colada Loader Example</h1>
|
||||
<pre>route.params: {{ route.params }}</pre>
|
||||
|
||||
<fieldset>
|
||||
<legend>Controls</legend>
|
||||
|
||||
<button @click="refresh()">Refresh</button>
|
||||
<button @click="reload()">Refetch</button>
|
||||
</fieldset>
|
||||
|
||||
<div class="flex items-center">
|
||||
<RouterLink :to="{ params: { userId: (Number(route.params.userId) || 0) - 1 } }">
|
||||
Previous
|
||||
{{ (Number(route.params.userId) || 0) - 1 }}
|
||||
</RouterLink>
|
||||
|
|
||||
<RouterLink :to="{ params: { userId: (Number(route.params.userId) || 0) + 1 } }">
|
||||
Next {{ (Number(route.params.userId) || 0) + 1 }}
|
||||
</RouterLink>
|
||||
</div>
|
||||
|
||||
<h2>State</h2>
|
||||
|
||||
<p>
|
||||
<code>status: {{ status }}</code>
|
||||
<br />
|
||||
<code>isLoading: {{ isLoading }}</code>
|
||||
</p>
|
||||
<pre v-if="error">Error: {{ error }}</pre>
|
||||
<pre v-else>{{ user == null ? String(user) : user }}</pre>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.green {
|
||||
background-color: #42b883;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #4a4a4a;
|
||||
padding: 16px;
|
||||
margin: 16px 0;
|
||||
border-radius: 8px;
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
legend {
|
||||
padding: 0 8px;
|
||||
color: #b3b3b3;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-right: 8px;
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #4a4a4a;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
background-color: #333333;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #444444;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #1e1e1e;
|
||||
padding: 16px;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #2a2a2a;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #42b883;
|
||||
text-decoration: none;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
color: #5ccfaa;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #e0e0e0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #42b883;
|
||||
margin-top: 24px;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user