React 结合 Graphql 学习记录

这篇博客介绍了如何使用Apollo Client与GraphQL进行交互,包括安装、初始化客户端、使用useQuery进行数据查询、缓存策略及更新、以及Mutation操作。通过实例展示了如何设置轮询、重新获取数据和直接更新缓存,确保应用数据与服务器同步。
摘要由CSDN通过智能技术生成

Get Start

1. Setup

npm install @apollo/client graphql

2. Initialize ApolloClient

import {
  ApolloClient,
  InMemoryCache,
  ApolloProvider,
  useQuery,
  gql
} from "@apollo/client";
const client = new ApolloClient({
  uri: 'https://48p1r2roz4.sse.codesandbox.io',
  cache: new InMemoryCache()
});
  • uri: graphql server 地址 
  • cache: is an instance of InMemoryCache, which Apollo Client uses to cache query results after fetching them.
// const client = ...

client
  .query({
    query: gql`
      query GetRates {
        rates(currency: "USD") {
          currency
        }
      }
    `
  })
  .then(result => console.log(result));

 3. Connect your client to React

import React from 'react';
import { render } from 'react-dom';
import {
  ApolloClient,
  InMemoryCache,
  ApolloProvider,
  useQuery,
  gql
} from "@apollo/client";

const client = new ApolloClient({
  uri: 'https://48p1r2roz4.sse.codesandbox.io',
  cache: new InMemoryCache()
});

function App() {
  return (
    <div>
      <h2>My first Apollo app 🚀</h2>
    </div>
  );
}

render(
  <ApolloProvider client={client}>    <App />  </ApolloProvider>,  document.getElementById('root'),
);

4. Fetch data with useQuery

const EXCHANGE_RATES = gql`
  query GetExchangeRates {
    rates(currency: "USD") {
      currency
      rate
    }
  }
`;
function ExchangeRates() {
  const { loading, error, data } = useQuery(EXCHANGE_RATES);
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return data.rates.map(({ currency, rate }) => (
    <div key={currency}>
      <p>
        {currency}: {rate}
      </p>
    </div>
  ));
}

Whenever this component renders, the useQuery hook automatically executes our query and returns a result object containing loadingerror, and data properties 

Updating cached query results

Apollo 会对查询结果自动做缓存。因此Apollo提供了 缓存策略Polling和refetching。

Polling

  轮询通过在指定的间隔定期执行查询,提供与服务器的近实时同步。要对查询启用轮询,请向useQuery钩子传递一个pollInterval配置选项,间隔时间为毫秒:

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

 通过将pollInterval设置为500,我们每0.5秒从服务器获取当前品种的映像。注意,如果将pollInterval设置为0,则查询不会轮询。

Refetching 

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

  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>
  );
}
<button onClick={() => refetch({
  breed: 'dalmatian' // Always refetches a dalmatian instead of original breed
})}>Refetch!</button>
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>
  );
}
notifyOnNetworkStatusChange: true

 notifyOnNetworkStatusChange: true 表示执行refetch方法,同时更新loading状态

缓存策略

const { loading, error, data } = useQuery(GET_DOGS, {
  fetchPolicy: "network-only",   // Used for first execution
  nextFetchPolicy: "cache-first" // Used for subsequent executions});

如果指定了nextFetchPolicy则fetchPolicy被用于第一次缓存

cache-first

阿波罗客户端首先对缓存执行查询。如果所有请求的数据都在缓存中,则返回该数据。否则,Apollo Client将对GraphQL服务器执行查询,并在缓存数据后返回该数据。 优先级最小化应用程序发送的网络请求的数量。 这是默认的获取策略。

cache-only

Apollo Client仅针对缓存执行查询。在这种情况下,它不会查询你的服务器。 如果缓存不包含所有请求字段的数据,仅缓存查询将抛出错误。

cache-and-network

Apollo Client对缓存和GraphQL服务器执行完整查询。如果服务器端查询的结果修改了缓存字段,查询将自动更新。 提供快速响应,同时帮助保持缓存数据与服务器数据一致

network-only

 阿波罗客户端对GraphQL服务器执行完整查询,而不首先检查缓存。查询结果存储在缓存中。 优先级与服务器数据保持一致,但不能在缓存数据可用时提供近乎即时的响应。

no-cache

类似于仅限网络,除了查询的结果不存储在缓存中。

standby

使用与缓存优先相同的逻辑,只是当底层字段值更改时,此查询不会自动更新。您仍然可以使用refetch和updateQueries手动更新这个查询。

 Mutation

执行更新服务器数据的操作。更新操作结果有俩种方式,重新请求、直接更新缓存数据。

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

const ADD_TODO = gql`
  mutation AddTodo($text: String!) {
    addTodo(text: $text) {
      id
      text
    }
  }
`;
function AddTodo() {
  let input;
  const [addTodo, { data, loading, error }] = useMutation(ADD_TODO);
  if (loading) return 'Submitting...';
  if (error) return `Submission error! ${error.message}`;

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

 给变量提供默认值

const [addTodo, { data, loading, error }] = useMutation(ADD_TODO, {
  variables: {
    text: "placeholder",
    someOtherVariable: 1234,
  },
});

Refetching queries

当插入数据执行完成后重新获取数据。查询入参使用最近一次参数。

// Refetches two queries after mutation completes
const [addTodo, { data, loading, error }] = useMutation(ADD_TODO, {
  refetchQueries: [
    GET_POST, // DocumentNode object parsed with gql
    'GetComments' // Query name
  ],
});
  • 参数一:A DocumentNode object parsed with the gql function
  • 参数二:执行查询的名字

Updating the cache directly

{
  "__typename": "Todo",
  "id": "5",
  "text": "Buy grapes 🍇"
}

Apollo  会根据__typename更新缓存,新缓存的对象不会自动添加到应该包含该字段的列表中。需要添加更新函数。

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

更改缓存可以立即更新视图结果,但是可能人为造成更新缓存结果不正确。可以更新缓存➕网络请求双重检测。

addTodo({
  variables: { type: input.value },
  update(cache, result) {
    // Update the cache as an approximation of server-side mutation effects
  },
  onQueryUpdated(observableQuery) {
    // Define any custom logic for determining whether to refetch
    if (shouldRefetchQuery(observableQuery)) {
      return observableQuery.refetch();
    }
  },
})

在onQueryUpdated中编写逻辑是否重新网络请求。如果网络请求数据和缓存数据不同,Apollo会自动更新缓存和视图。 

未完待续。。。

参考文档

Apollo官网链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值