跳到主要内容
npm install --save @data-client/graphql

定义 Endpoint 与 Schema​

schema/endpoint.ts
export const gql = new GQLEndpoint('https://nosy-baritone.glitch.me');
export default gql;
schema/User.ts
import { GQLEntity } from '@data-client/graphql';

export default class User extends GQLEntity {
name: string | null = null;
email = '';
age = 0;
}

Entity 是不可变的。在 TypeScript 中使用 readonly 来强制这一点。

提示

使用 GQLEntity 并非必需,但对实现数据一致性很重要。

查询图​

pages/UserDetail.tsx
import { useSuspense } from '@data-client/react';
import User from 'schema/User';
import gql from 'schema/endpoint';

export const userDetail = gql.query(
(v: { name: string }) => `query UserDetail($name: String!) {
user(name: $name) {
id
name
email
}
}`,
{ user: User },
);

export default function UserDetail({ name }: { name: string }) {
const { user } = useSuspense(userDetail, { name });
return (
<article>
<h2>{user.name}</h2>
<div>{user.email}</div>
</article>
);
}

useSuspense() 保证访问到足够新鲜的数据。这意味着它可能会发起网络请求,并可能挂起直到获取完成。参数变化会使其访问相应的数据,这有时也会引发新的网络请求和/或挂起。

  • 请求由中心统一控制,因此会自动去重
  • 数据集中存放并经过规范化,即使使用不同的 endpoint,也能保证各处使用的一致性。
    • (例如:从列表视图进入某一条目的详情页时,会立即显示与列表相同的数据,而无需重新获取。)
SWAPI 演示
import { useSuspense } from '@data-client/react';
import { GQLEndpoint, GQLEntity } from '@data-client/graphql';

const gql = new GQLEndpoint(
  'https://swapi-graphql.netlify.app/graphql',
);
class Person extends GQLEntity {
  readonly id: string = '';
  readonly name: string = '';
  readonly height: string = '';
}
const PageInfo = {
  hasNextPage: false,
  startCursor: '',
  endCursor: '',
};
const allPeople = gql.query(
  (v: { first?: number; after?: string }) => `
query People($first: Int, $after:String) {
  allPeople(first: $first, after:$after) {
    people{
      id,name,height
    },
    pageInfo {
      hasNextPage,
      startCursor,
      endCursor
    }
  }
}
`,
  { allPeople: { people: [Person], pageInfo: PageInfo } },
);
function StarPeople() {
  const { people, pageInfo } = useSuspense(allPeople, {
    first: 5,
  }).allPeople;
  return (
    <div>
      {people.map(person => (
        <div key={person.id}>
          name: {person.name} height: {person.height}
        </div>
      ))}
    </div>
  );
}
render(<StarPeople />);
结果
Store▶

变更图​

我们使用 SWAPI 作为示例,因为它提供了变更操作。

pages/CreateReview.tsx
import { useController } from '@data-client/react';
import { GQLEndpoint, GQLEntity } from '@data-client/graphql';

const gql = new GQLEndpoint(
'https://swapi-graphql.netlify.app/graphql',
);

class Review extends GQLEntity {
readonly stars: number = 0;
readonly commentary: string = '';
}

const createReview = gql.mutation(
(v: {
ep: string;
review: { stars: number; commentary: string };
}) => `mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
stars
commentary
}
}`,
{ createReview: Review },
);

export default function NewReviewForm() {
const ctrl = useController();
return (
<Form onSubmit={variables => ctrl.fetch(createReview, variables)}>
<FormField name="ep" />
<FormField name="review" type="compound" />
</Form>
);
}

GQLEndpoint.query 或 GQLEndpoint.mutate 的第一个参数可以是查询字符串, _也可以_是返回查询字符串的函数。使用后者的主要价值在于可以约束函数参数的类型。

与 REST 混用的演示​

探索 github-app 示例

更多演示