Зачем нужны refetchQueries? - PullRequest
0 голосов
/ 31 октября 2019

Я следую учебному пособию по GraphQL, в видео автор не использует refetchQueries для deleteMutation и все хорошо работает с обновлениями и мутациями пользовательского интерфейса. Но здесь в проекте обновляется код изолированной программной среды, и теперь для этой операции используется refetchQuery в компоненте Job -> line 20 -> deleteJob (): codeSandBox .

У меня есть похожая проблема в моем приложении, которая не обновляет пользовательский интерфейс автоматически без повтора запросов, выполняемых повсеместно. Разве Apollo не должен автоматически применять кеш Apollo через apollo-cache-inmemory, выполнять мутацию и обновлять пользовательский интерфейс в такой мутации, если я правильно понимаю.

Пример из коробки с apollo-boost:

export default gql`
mutation deleteItem($id: uuid!) {
  delete_item(where: {id:{_eq: $id }}){
    returning {
      id
    }
  }
}`;
 const onDeleteItem = (id) => {
    deleteItem({
      variables: { id },
    });
  };

Есть предложения или опыт по этому поводу?

1 Ответ

2 голосов
/ 01 ноября 2019

Ответ относительно прост: в GraphQL нет универсального способа сообщить клиенту, что объект был удален. Давайте сначала сравним это с обновлением мутации. Представьте, что мы обновляем одно из заданий, которое у нас уже есть в нашем кэше. Сначала кеш (упрощенно, не совсем так, как выглядит внутри Apollo):

{
  "Query": {
    "jobs": ["Job:1", "Job:2"],
  },
  "Job:1": {
    "__typename": "Job",
    "id": 1,
    "company": "Big Corp",
    "title": "Sales Specialist"
  },
  "Job:2": {
    "__typename": "Job",
    "id": 2,
    "company": "Big Corp",
    "title": "GraphQL Expert"
  }
}

Если Apollo теперь получает ответ от мутации обновления, которая выглядит следующим образом:

{
  "data": {
    "updateJob": {
      "__typename": "Job",
      "id": 2,
      "company": "Big Corp",
      "title": "GraphQL Unicorn"
    }
  }
}

Он может использовать функцию dataIdFromObject, чтобы понять, что объект принадлежит ключу кэша "Job:2" в нашем нормализованном кэше. Аполлон может предположить, что эта версия новее старой, и объединить ключи с предпочтением более нового результата. Наш кеш теперь выглядит следующим образом:

{
  "Query": {
    "jobs": ["Job:1", "Job:2"],
  },
  "Job:1": { ... },
  "Job:2": {
    "__typename": "Job",
    "id": 2,
    "company": "Big Corp",
    "title": "GraphQL Unicorn" // updated!
  }
}

Тогда запрос "jobs" автоматически обновится с новым заданием, поскольку он просто ссылается на задание и не хранит сам объект. Большой! Но теперь сравните результат с функцией удаления:

{
  "data": {
    "deleteJob": {
      "returning": {
        "id": 2,
      }
    }
  }
}

Результатом этого запроса может быть что угодно. Аполлон не может знать, что вы только что удалили работу с определенным идентификатором. Возможно, если бы в спецификации GraphQL было что-то вроде магического «__isDeleted» и мы получили бы что-то вроде:

{
  "data": {
    "deleteJob": {
        "__typename": "Job",
        "__isDeleted": true,
        "id": 2,
      }
    }
  }
}

Мы могли бы дать нашей реализации кэша подсказку, что сущности с __isDeleted: true должны быть удалены из всех ссылокзапросы. Но, к сожалению, этого не существует. Это не так уж плохо, но мы можем либо использовать refetchQuery для запуска повторного получения другого запроса, либо мы можем обновить другой запрос вручную :

const deleteJob = useMutation(DELETE_JOB, {
  update(store, response) {
    const data = store.readQuery({ query: GET_JOBS });
    data.jobs = data.jobs.filter(job => job.id !== response.deleteJob.returning.id);
    store.writeQuery({ query: GET_JOBS, data });
  }
});
...