0
点赞
收藏
分享

微信扫一扫

apollo client学习笔记

小猪肥 2021-09-25 阅读 30
日记本

查询用法:

import { gql, useQuery } from '@apollo/client';

const GET_DOGS = gql`
  query GetDogs {
    dogs {
      id
      breed
    }
  }
`;
function Dogs({ onDogSelected }) {
  const { loading, error, data } = useQuery(GET_DOGS);

  if (loading) return 'Loading...';
  if (error) return `Error! ${error.message}`;

  return (
    <select name="dog" onChange={onDogSelected}>
      {data.dogs.map(dog => (
        <option key={dog.id} value={dog.breed}>
          {dog.breed}
        </option>
      ))}
    </select>
  );
}

无需定义state, const { loading, error, data } = useQuery(GET_DOGS);即是当前的状态。

缓存查询结果

每次查询的结果都会自动缓存在内存之中,下次请求结果将用本地缓存

查询的时候携带参数

const GET_DOG_PHOTO = gql`
  query Dog($breed: String!) {
    dog(breed: $breed) {
      id
      displayImage
    }
  }
`;

function DogPhoto({ breed }) {
  const { loading, error, data } = useQuery(GET_DOG_PHOTO, {
    variables: { breed },
  });

  if (loading) return null;
  if (error) return `Error! ${error}`;

  return (
    <img src={data.dog.displayImage} style={{ height: 100, width: 100 }} />
  );
}

刷新缓存

function DogPhoto({ breed }) {
  const { loading, error, data } = useQuery(GET_DOG_PHOTO, {
    variables: { breed },
    pollInterval: 500,
  });

  if (loading) return null;
  if (error) return `Error! ${error}`;

  return (
    <img src={data.dog.displayImage} style={{ height: 100, width: 100 }} />
  );
}

或者调用refetch方法手动刷新:

import { NetworkStatus } from '@apollo/client';

function DogPhoto({ breed }) {
  const { loading, error, data, refetch, networkStatus } = useQuery(
    GET_DOG_PHOTO,
    {
      variables: { breed },
      notifyOnNetworkStatusChange: true,
    },
  );

  if (networkStatus === NetworkStatus.refetch) return 'Refetching!';
  if (loading) return null;
  if (error) return `Error! ${error}`;

  return (
    <div>
      <img src={data.dog.displayImage} style={{ height: 100, width: 100 }} />
      <button onClick={() => refetch()}>Refetch!</button>
    </div>
  );
}

手动获取数据

import React from 'react';
import { useLazyQuery } from '@apollo/client';

function DelayedQuery() {
  const [getDog, { loading, data }] = useLazyQuery(GET_DOG_PHOTO);

  if (loading) return <p>Loading ...</p>;

  return (
    <div>
      {data && data.dog && <img src={data.dog.displayImage} />}
      <button onClick={() => getDog({ variables: { breed: 'bulldog' } })}>
        Click me!
      </button>
    </div>
  );
}

获取数据的策略(是否每次从网络获取),

默认是从本地缓存获取(cache-first),要修改这个策略可以在query的时候指定:

const { loading, error, data } = useQuery(GET_DOGS, {
  fetchPolicy: "network-only"
});

支持的策略列表为:
cache-first:Apollo Client首先对缓存执行查询。如果所有请求的数据都在缓存中,则返回该数据。否则,Apollo Client将对GraphQL服务器执行查询,并在缓存数据后返回该数据。

优先级最小化应用程序发送的网络请求数量。

这是默认的获取策略。
cache-only:Apollo Client只对缓存执行查询。在这种情况下,它从不查询您的服务器。

如果缓存不包含所有请求字段的数据,则仅缓存查询将抛出错误。

cache-and-network:Apollo Client对缓存和GraphQL服务器执行完整的查询。如果服务器端查询的结果修改了缓存字段,则查询将自动更新。

提供快速响应,同时也有助于保持缓存数据与服务器数据一致
network-only:Apollo Client对GraphQL服务器执行完整的查询,而不首先检查缓存。查询的结果存储在缓存中。

优先考虑与服务器数据的一致性,但不能在缓存数据可用时提供近乎即时的响应。

no-cache:服务器请求数据本地不做缓存
standby:使用与cache-first相同的逻辑,只是此查询在基础字段值更改时不会自动更新。您仍然可以使用refetch和updateQueries手动更新该查询。

添加、更新数据

import { gql, useMutation } from '@apollo/client';

const ADD_TODO = gql`
  mutation AddTodo($type: String!) {
    addTodo(type: $type) {
      id
      type
    }
  }
`;
function AddTodo() {
  let input;
  const [addTodo, { data }] = useMutation(ADD_TODO);

  return (
    <div>
      <form
        onSubmit={e => {
          e.preventDefault();
          addTodo({ variables: { type: input.value } });
          input.value = '';
        }}
      >
        <input
          ref={node => {
            input = node;
          }}
        />
        <button type="submit">Add Todo</button>
      </form>
    </div>
  );
}

如上,useMutation不会立即执行ADD_TODO,而是会返回一个函数(addTodo),这个函数需要在需要的时候手动执行,如上是在onSubmit里面执行的:

onSubmit={e => {
          e.preventDefault();
          addTodo({ variables: { type: input.value } });
          input.value = '';
        }}

更新数据

const UPDATE_TODO = gql`
  mutation UpdateTodo($id: String!, $type: String!) {
    updateTodo(id: $id, type: $type) {
      id
      type
    }
  }
`;

function Todos() {
  const { loading, error, data } = useQuery(GET_TODOS);
  const [updateTodo] = useMutation(UPDATE_TODO);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return data.todos.map(({ id, type }) => {
    let input;

    return (
      <div key={id}>
        <p>{type}</p>
        <form
          onSubmit={e => {
            e.preventDefault();
            updateTodo({ variables: { id, type: input.value } });
            input.value = '';
          }}
        >
          <input
            ref={node => {
              input = node;
            }}
          />
          <button type="submit">Update Todo</button>
        </form>
      </div>
    );
  });
}

上面onSubmit之后,服务器端数据会更新,而且本地缓存数据也会自动更新,界面会重新render.

更新多项数据

如果是列表中删除或者新增一项,本地数据不会自动更新,需要调用update方法来手动更新:

const GET_TODOS = gql`
  query GetTodos {
    todos {
      id
    }
  }
`;

function AddTodo() {
  let input;
  const [addTodo] = useMutation(ADD_TODO, {
    update(cache, { data: { addTodo } }) {
      cache.modify({
        fields: {
          todos(existingTodos = []) {
            const newTodoRef = cache.writeFragment({
              data: addTodo,
              fragment: gql`
                fragment NewTodo on Todo {
                  id
                  type
                }
              `
            });
            return [...existingTodos, newTodoRef];
          }
        }
      });
    }
  });

  return (
    <div>
      <form
        onSubmit={e => {
          e.preventDefault();
          addTodo({ variables: { type: input.value } });
          input.value = "";
        }}
      >
        <input
          ref={node => {
            input = node;
          }}
        />
        <button type="submit">Add Todo</button>
      </form>
    </div>
  );
}

数据订阅

通常不要使用订阅功能,使用轮询、重新获取等方式都能满足一般需求,数据订阅基于websockt,服务器端有更新之后,会主动更新客户端数据,主要用于以下情况:
1、对大对象的微小的增量变化。反复轮询大型对象的开销很大,特别是在对象的大部分字段很少更改的情况下。相反,您可以通过查询获取对象的初始状态,并且您的服务器可以在更新发生时主动地将更新推送到各个字段。
2、低延迟的实时更新。例如,聊天应用程序的客户机希望在新消息可用时立即接收它们。
服务器端实现:

type Subscription {
  commentAdded(postID: ID!): Comment
}

客户端:

const COMMENTS_SUBSCRIPTION = gql`
  subscription OnCommentAdded($postID: ID!) {
    commentAdded(postID: $postID) {
      id
      content
    }
  }
`;
举报

相关推荐

0 条评论