跳到主要内容

数据变更

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

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

import { useController } from '@data-client/react';
import { TodoResource, type Todo } from './TodoResource';

export default function TodoItem({ todo }: { todo: Todo }) {
  const ctrl = useController();
  const handleChange = e =>
    ctrl.fetch(
      TodoResource.partialUpdate,
      { id: todo.id },
      { completed: e.currentTarget.checked },
    );
  const handleDelete = () =>
    ctrl.fetch(TodoResource.delete, {
      id: todo.id,
    });
  return (
    <div className="listItem nogap">
      <label>
        <input
          type="checkbox"
          checked={todo.completed}
          onChange={handleChange}
        />
        {todo.completed ? <s>{todo.title}</s> : todo.title}
      </label>
      <CancelButton onClick={handleDelete} />
    </div>
  );
}
结果
Store▶

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,
    };
  },
});
结果
Store▶

getOptimisticResponse 就像使用更新函数的 setState。Snapshot 提供对先前 store 值的类型安全访问,我们用它来返回_预期的_ fetch 响应。

Reactive Data Client 能在任何可能的网络故障或竞态条件下确保数据完整性,因此你无需担心网络故障、多次变更调用编辑同一份数据,或异步编程中的其他常见问题。

跟踪变更的加载状态​

useLoading() 通过跟踪异步函数的加载状态和错误状态来增强它们。

import { useLoading, useController } from '@data-client/react';
import { PostResource } from './PostResource';
import PostForm from './PostForm';

export default function PostCreate({ navigateToPost }) {
  const ctrl = useController();
  const [handleSubmit, loading, error] = useLoading(
    async data => {
      const post = await ctrl.fetch(PostResource.getList.push, data);
      navigateToPost(post.id);
    },
    [ctrl],
  );
  return (
    <PostForm onSubmit={handleSubmit} loading={loading} error={error} />
  );
}
结果
Store▶