DataClientPlugin
Plugin de Vue que crea el store y el
Controller, y los proporciona a todos los componentes de la aplicación. Instálalo una sola vez,
antes de app.mount(); los composables solo funcionan en componentes de una aplicación en la que esté instalado.
import { createApp } from 'vue';
import { DataClientPlugin } from '@data-client/vue';
import App from './App.vue';
const app = createApp(App);
app.use(DataClientPlugin);
app.mount('#app');
Los Managers se inician cuando se instala el plugin y se detienen cuando la aplicación se desmonta.
Opciones
app.use(DataClientPlugin, options);
interface ProvideOptions {
managers?: Manager[];
initialState?: State<unknown>;
Controller?: new (props: { gcPolicy: GCInterface }) => Controller;
gcPolicy?: GCInterface;
}
managers?: Manager[]
Lista de Managers que se usarán. Es el principal punto de extensibilidad del store.
Por defecto es getDefaultManagers(), que también puede usarse para ampliar los valores predeterminados.
import { createApp } from 'vue';
import { DataClientPlugin, getDefaultManagers } from '@data-client/vue';
import App from './App.vue';
import MyManager from './MyManager';
const app = createApp(App);
app.use(DataClientPlugin, {
managers: [...getDefaultManagers(), new MyManager()],
});
Predeterminado en producción:
[new NetworkManager(), new SubscriptionManager(PollingSubscription)];
Predeterminado en desarrollo:
[
new DevToolsManager(),
new NetworkManager(),
new SubscriptionManager(PollingSubscription),
];
initialState?: State<unknown>
En lugar de empezar con una caché vacía, puedes proporcionar tu propio estado inicial. Esto puede ser útil para pruebas o para rehidratar el estado de la caché al usar renderizado del lado del servidor. mockInitialState() construye uno a partir de fixtures.
app.use(DataClientPlugin, { initialState: window.__INITIAL_STATE__ });
export interface State<T> {
readonly entities: {
readonly [entityKey: string]: { readonly [pk: string]: T } | undefined;
};
readonly endpoints: {
readonly [key: string]: unknown | PK[] | PK | undefined;
};
readonly indexes: NormalizedIndex;
readonly meta: {
readonly [key: string]: {
readonly date: number;
readonly fetchedAt: number;
readonly expiresAt: number;
readonly prevExpiresAt?: number;
readonly error?: ErrorTypes;
readonly invalidated?: boolean;
readonly errorPolicy?: 'hard' | 'soft' | undefined;
};
};
readonly entitiesMeta: {
readonly [entityKey: string]: {
readonly [pk: string]: {
readonly date: number;
readonly expiresAt: number;
readonly fetchedAt: number;
};
};
};
readonly optimistic: (SetResponseAction | OptimisticAction)[];
readonly lastReset: number;
}
Controller?: clase Controller
Te permite extender Controller para ofrecer funcionalidad adicional. Puede ser útil si tienes acciones adicionales que quieres despachar a Managers personalizados.
import { createApp } from 'vue';
import { Controller, DataClientPlugin } from '@data-client/vue';
import App from './App.vue';
export class MyController extends Controller {
doSomething = () => {
console.log('hi');
};
}
const app = createApp(App);
app.use(DataClientPlugin, { Controller: MyController });
useController() y $dataClient devuelven entonces una instancia de MyController,
pero siguen tipados como Controller. Usa una conversión de tipo para acceder a los miembros añadidos:
import { useController } from '@data-client/vue';
import type { MyController } from './main';
const ctrl = useController() as MyController;
ctrl.doSomething();
gcPolicy?: GCInterface
Elimina datos del store cuando ningún componente los usa y se han vuelto obsoletos. El valor predeterminado es
new GCPolicy(); pasa uno para cambiar la frecuencia del barrido o cuánto tiempo se conservan los datos sin usar.
import { createApp } from 'vue';
import { DataClientPlugin, GCPolicy } from '@data-client/vue';
import App from './App.vue';
const app = createApp(App);
app.use(DataClientPlugin, {
// sweep every 10 minutes
gcPolicy: new GCPolicy({ intervalMS: 60 * 1000 * 10 }),
});
new GCPolicy({
// how often to sweep (default 5 minutes)
intervalMS: 60 * 1000 * 5,
// how many stale lifetimes before data is removed (default 2)
expiryMultiplier: 2,
// or choose when unused data is removed (replaces expiryMultiplier)
// here: one minute after it goes stale
expiresAt: ({ expiresAt }) => expiresAt + 60 * 1000,
});
$dataClient
El plugin también añade el Controller como propiedad global $dataClient, de modo que
las plantillas y los componentes con Options API (como this.$dataClient) pueden usarlo sin
useController(). Está tipado como Controller sin configuración adicional.
<script setup lang="ts">
import { TodoResource } from '@/resources/Todo';
defineProps<{ id: number }>();
</script>
<template>
<button @click="$dataClient.fetch(TodoResource.delete, { id })">
Delete
</button>
</template>
Uso de composables
Los composables como useSuspense() deben ejecutarse durante el setup de un componente, para que Vue
sepa qué store de qué aplicación usar. Esperarlos con await requiere <script setup>: en un
async setup() escrito a mano, los composables llamados después del primer await pierden la instancia del componente y lanzan un error.
<script setup lang="ts">
import { useSuspense } from '@data-client/vue';
import { TodoResource } from '@/resources/Todo';
import { UserResource } from '@/resources/User';
const todo = await useSuspense(TodoResource.get, { id: 1 });
// still works after the await
const user = await useSuspense(UserResource.get, {
id: todo.value.userId,
});
</script>
Los componentes que hacen await deben renderizarse dentro de un límite de <Suspense>.