defineColadaLoader
All checks were successful
/ depcheck (push) Successful in 1m12s
/ build-and-deploy-to-vercel (push) Successful in 2m2s
/ playwright (push) Successful in 1m25s

This commit is contained in:
严浩
2024-12-20 14:53:31 +08:00
parent a8ce2f39e2
commit 89eae5bcbb
5 changed files with 160 additions and 0 deletions

View 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>

View 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>