GraphQL 入門: Apollo Client 存儲API

GraphQL 入門: 簡介
GraphQL 入門: Apollo Client - 簡介
GraphQL 入門: Apollo Client - 安裝和配置選項
GraphQL 入門: Apollo Client - 鏈接到數據
GraphQL 入門: Apollo Client - 網絡層
GraphQL 入門: Apollo Client - 開發調試工具
GraphQL 入門: Apollo Client - 持久化GraphQL查詢概要
GraphQL 入門: Apollo Client - 存儲API
GraphQL 入門: Apollo Client - 查詢(Batching)合併html

Apollo Client 使用四個方法來控制存儲:readQuery, readFragment, writeQuery, writeFragment. Apollo Client 的這些實例方法可讓你直接讀寫緩存. react

用這四個方法可以讓你自定義Apollo Client的行爲. 下面咱們介紹每一個方法的細節.segmentfault

從存儲讀取查詢

第一個和存儲交互的方法是readQuery. 該方法用於從根查詢開始讀取緩存數據, 下面是讀取數據的例子:後端

const data = client.readQuery({
  query: gql`
  {
    todo(id: 1) {
      id
      text
      completed
    }
        
  }
  `
});

若是數據在緩存中已經存儲, 它將會直接返回並存儲到組件的data屬性, 而不須要向服務器請求, 若是在緩存中找不到查詢對應的數據, 將會拋出一個錯誤.api

你能夠在應用中任何地方使用一個查詢, 還能夠傳入變量:瀏覽器

import { TodoQuery } form './TodoGraphQL';

const data = client.readQuery({
  query: TodoQuery,
  variables: {
    id: 5
  }
});

readQueryquery 相似, 可是readQuery 不會發送請求到服務器, 它老是指望從緩存中查詢數據, 若是緩存中找不到對應的數據, 將會拋出一個錯誤.緩存

從存儲讀取片斷

有時候你但願重緩存中讀取任意的數據, 而不單單是根查詢類型. 對此有一個 readFragment() 方法用於這類用途. 該方法接受 GraphQL 片斷和一個 ID, 並返回 ID 對應的數據片斷.服務器

client.readFragment({
  id: '5',
  fragment: gql`
    fragment todo on Todo {
      id
      text
      completed
    }
  `
});

id 應該是一個由 dataIdFromObject 函數返回的字符串, 這個字符串是在 Apollo Client 初始化的時候經過 dataIdFromObject 函數進行定義.網絡

const client = new ApolloClient({
  dataIdFromObject: o => {
    if(o.__typename != null && o.id != null) {
      return `${o.__typename}-${o.id}`;
    }
  }
});

由於在id前面添加了變量__typename, 而後id的值變爲Todo5.函數

向存儲寫入查詢和片斷

和讀取查詢和片斷對應的還有 writeQuery()writeFragment() 方法. 這兩個方法讓你可以更新緩存中的數據, 用於模擬來自服務器的數據更新. 可是注意這些數據沒有持久化到後端, 若是你刷新你的瀏覽器, 這些更新的數據將會丟失.

用戶不會注意到有什麼區別, 若是更新數據要對全部用戶可見, 須要把更新的數據持久化到後端服務器.

writeQuerywriteFragment 的優勢是, 它們讓你可以修改緩存中的數據以確保數據可以同步到服務器, 而且在執行一次服務器徹底刷新的時候不會丟失你的數據更新. 這讓你可以部分的修改客戶端數據, 給用戶提供更好的體驗.

writeQuery()readQuery 有相同的接口, 和 readQuery 不一樣的是 writeQuery 還有一個 data 參數. data 對象的結構必須和服務器返回的JSON結果的結構相同.

client.writeQuery({
  query: gql`
    {
      todo(id: 1) {
        completed
      }
    }
  `,
  data: {
    todo: {
      completed: true
    },
  },
});

一樣的, writeFragment()readFragment() 也有相同的接口, 而且多一個 data 參數. id 遵循和 readFragment() 相同的規則:

client.writeFragment({
  id: '5',
  fragment: gql`
    fragment todo in Todo {
      completed
    }
  `,
  data: {
    completed: true
  }
});

這四個方法讓你可以徹底的控制緩存中的數據.

使用讀和寫來更新數據

由於從緩存中獲取的數據只是一份拷貝, 不影響底層的存儲.

const query = gql`
  {
    todos {
      id
      text
      completed
    }
  }
`;

const data = client.readQuery({
  query
});

data.todos.push({
  id: 5,
  text: 'Hello, world!',
  completed: false
});

client.writeQuery({
  query,
  data
});

在一個Mutation以後執行更新

const text = 'Hello, world!';
client.mutate({
  // GraphQL Mutation 更新語句
  mutation: gql`
    mutation ($text: String!) {
      createTodo(text: $text) {
        id
        text
        completed
      }
    }
  `,
  // 變量
  variables: {
    text,
  },
  optimisticResponse: {
    createTodo: {
      id: -1, // Fake id
      text,
      completed: false,
    },
  },
  // 更新函數
  // 用Mutation返回的結果對存儲進行更新, 並觸發React UI組件的從新渲染
  update: (proxy, mutationResult) => {
    const query = gql`
      {
        todos {
          id
          text
          completed
        }
      }
    `;
    // 從緩存中讀取數據
    const data = proxy.readQuery({
      query,
    });
    // 用Mutation的結果更新數據
    data.todos.push(mutationResult.createTodo);
    // 寫回緩存
    proxy.writeQuery({
      query,
      data,
    });
  },
});

update 函數有兩個參數:

  • proxy 是一個 DataProxy 對象, 主要用於與底層存儲進行數據交互

  • mutationResult 是一個Mutation操做的響應, 能夠是一個樂觀應答, 或服務器實際的應答.

updateQueries

也可使用updateQueries回調函數對數據進行更新. 詳細的API接口可參考 updateQueries

updateQueries 也是基於 Mutation 的返回結果對存儲進行更新, 和 update 函數不一樣的是, 他會覆蓋全部重疊的數據節點

參考資料

相關文章
相關標籤/搜索