数据变更
将我们的创建、更新和删除 endpoint 与 Controller.fetch() 配合使用,会以响应式的方式原子地(同时)更新_所有_相关组件。
useController() 让组件可以使用这个全局的、功能增强版的 setState()。
TodoResource
TodoItem.vue
CreateTodo.vue
TodoList.vue
<script setup lang="ts"> import { useController } from '@data-client/vue'; import { TodoResource, type Todo } from './TodoResource'; const props = defineProps<{ todo: Todo }>(); const ctrl = useController(); const handleChange = (e: Event) => ctrl.fetch( TodoResource.partialUpdate, { id: props.todo.id }, { completed: (e.target as HTMLInputElement).checked }, ); const handleDelete = () => ctrl.fetch(TodoResource.delete, { id: props.todo.id, }); </script> <template> <div class="listItem nogap"> <label> <input type="checkbox" :checked="todo.completed" @change="handleChange" /> <s v-if="todo.completed">{{ todo.title }}</s> <template v-else>{{ todo.title }}</template> </label> <CancelButton @click="handleDelete" /> </div> </template>
Data Client 不会触发级联失效,也不需要手写更新函数,而是利用 fetch 响应以响应式的方式更新相关组件。
基于先前状态的乐观变更
Post
PostResource
PostItem.vue
TotalVotes.vue
PostList.vue
import { resource } from '@data-client/rest'; import { Post } from './Post'; export { Post }; export const PostResource = resource({ path: '/posts/:id', searchParams: {} as { userId?: string | number } | undefined, schema: Post, }).extend('vote', { path: '/posts/:id/vote', method: 'POST', body: undefined, schema: Post, getOptimisticResponse(snapshot, { id }) { const post = snapshot.get(Post, { id }); if (!post) throw snapshot.abort; return { id, votes: post.votes + 1, }; }, });
getOptimisticResponse 就像使用更新函数的 setState。Snapshot 提供对先前 store 值的类型安全访问,我们用它来返回_预期的_ fetch 响应。
Reactive Data Client 能在任何可能的网络故障或竞态条件下确保数据完整性,因此你无需担心网络故障、多次变更调用编辑同一份数据,或异步编程中的其他常见问题。
跟踪变更的加载状态
useLoading() 通过跟踪异步函数的加载状态和错误状态来增强它们。
PostResource
PostDetail.vue
PostForm.vue
PostCreate.vue
Navigation.vue
<script setup lang="ts"> import { useLoading, useController } from '@data-client/vue'; import { PostResource } from './PostResource'; import PostForm from './PostForm.vue'; const emit = defineEmits<{ navigateToPost: [id: number] }>(); const ctrl = useController(); const [handleSubmit, loading, error] = useLoading( async (data: FormData) => { const post = await ctrl.fetch(PostResource.getList.push, data); emit('navigateToPost', post.id); }, ); </script> <template> <PostForm @submit="handleSubmit" :loading="loading" :error="error" /> </template>