Pular para o conteúdo principal
npm install --save @data-client/graphql

Defina o Endpoint e o 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;
}

Entitys são imutáveis. Use readonly em TypeScript para garantir isso.

dica

Usar GQLEntities não é obrigatório, mas é importante para alcançar consistência dos dados.

Consulte o grafo​

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() garante acesso a dados com atualidade suficiente. Isso significa que ele pode fazer chamadas de rede e pode suspender até que o fetch seja concluído. Mudanças nos parâmetros resultam no acesso aos dados apropriados, o que também às vezes resulta em novas chamadas de rede e/ou suspensões.

  • Os fetches são controlados de forma centralizada e, portanto, deduplicados automaticamente
  • Os dados são centralizados e normalizados, garantindo consistência entre os usos, mesmo com endpoints diferentes.
    • (Por exemplo: navegar de uma lista para uma página de detalhes de um único item mostrará instantaneamente os mesmos dados da lista, sem exigir um novo fetch.)
Demo da 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 />);
Resultado
Store▶

Modifique o grafo​

Estamos usando a SWAPI como exemplo, já que ela oferece mutações.

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>
);
}

O primeiro argumento de GQLEndpoint.query ou GQLEndpoint.mutate é a string da query ou uma função que retorna a string da query. O principal valor de usar a segunda opção é impor os tipos dos argumentos da função.

Demo combinando com REST​

Explore o exemplo github-app

More Demos