跳到主要内容

数据变更

将我们的创建、更新和删除 endpoint 与 Controller.fetch() 配合使用,会以响应式的方式原子地(同时)更新_所有_相关组件。

useController() 让组件可以使用这个全局的、功能增强版的 setState()。

<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 响应以响应式的方式更新相关组件。

基于先前状态的乐观变更​

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() 通过跟踪异步函数的加载状态和错误状态来增强它们。

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