Как мне обновить кеш grapqhl с помощью urql после мутации, когда исходный ответ на запрос не включает требуемое __typename?
В моей ситуации 4 компонента вложены друг в друга в следующем порядке: Products
(страница), ProductList
, ProductListItem
, а также CrossSellForm
.
Products
выполняет запрос graphql (используя urql) как таковой:
const productsQuery = `
query {
products {
id
title
imageSrc
crossSells {
id
type
title
}
}
}
`;
...
const [response] = useQuery({
query: productsQuery,
});
const { data: { products = [] } = {}, fetching, error } = response;
...
<ProductList products={products} />
products
возвращает массив Products
который содержит поле, crossSells
, который возвращает массив CrossSells
. Products
распространяется вниз к CrossSellForm
, который содержит запрос на изменение, который возвращает массив CrossSells
.
Проблема в том, что когда я отправляю crossSellForm, запрос проходит успешно, но crossSells
сведущий Products
не обновляется, а пользовательский интерфейс отражает устаревшие данные. Это происходит только тогда, когда начальная загрузка вProducts
не содержит crossSells
, поэтому первоначальный ответ выглядит примерно так:
{
data: {
products: [
{
id: '123123',
title: 'Nice',
imageSrc: 'https://image.com',
crossSells: [],
__typename: "Product"
},
...
]
}
}
}
Если есть существующий crossSell
, проблем нет, интерфейс обновляется правильно, и ответ выглядит следующим образом:
{
data: {
products: [
{
id: '123123',
title: 'Nice',
imageSrc: 'https://image.com',
crossSells: [
{
id: 40,
title: 'Nice Stuff',
type: 'byVendor',
__typename: 'CrossSell'
}
],
__typename: "Product"
},
...
]
}
}
}
Я немного прочитал о механизме кэширования urql на https://formidable.com/open-source/urql/docs/basics/, и, насколько я понимаю, он использует кеш документа, поэтому он кэширует документ на основе__typename
. Если запрос запрашивает что-то с таким же__typename
он вытащит его из кеша. Еслиmutation
происходит с тем же __typename
он сделает недействительными все объекты в кеше с этим __typename
так что в следующий раз, когда пользователь получит объект с этим __typename
он выполнит сетевой запрос вместо кеширования.
Я думаю, что происходит в исходной ситуации, когда есть products
но нет crossSells
отправка формы прошла успешно, но Products
страница не обновляется, потому что нет ссылки на объект с __typename
из CrossSell
, но во второй ситуации происходит остановка кеша и повторное выполнение запроса, обновление продуктов и перекрестных продаж, а также надлежащее обновление пользовательского интерфейса.
Мне очень понравился опыт использования перехватчиков urql с компонентами React, и я хочу продолжить, но я не уверен, как я могу решить эту проблему, не прибегая к другому инструменту.
Я попытался принудительно выполнить повторный рендеринг при отправке формы, используя советы из: Как заставить компонент повторно рендерить с помощью хуков в React? но он сталкивается с той же проблемой, когдаProducts
снова будет извлекаться из кеша и crossSells
вернет пустой массив. Я думал об изменении RequestPolicy urql только на сеть вместе с принудительным повторным рендерингом, но думал, что повторная выборка каждый раз будет излишне затратной. Решение, которое я пробую сейчас, - это переместить все состояние в редукцию, единый источник истины, чтобы любое обновлениеcrossSells
будет распространяться должным образом, и хотя я уверен, что он будет работать, это также будет означать, что я откажусь от удобства, которое у меня было с крючками для стандартного шаблона redux.
Как я могу аккуратно обновить Products
с участием crossSells
при отправке формы в CrossSellForm
, все еще используя urql и хуки?
1 ответ
Основной участник здесь
Как вы уже обнаружили, для этого есть открытая проблема, в которой подробно описывается неотъемлемая проблема нашего простого кэша по умолчанию. Это кеш документов, поэтому он не подходит для более сложных задач, где может помочь нормализация.
Когда у нас есть пустой массив данных, нет никаких указаний на необходимость повторной выборки конкретного результата.
Вместо использования сетевой политики вы можете попробовать кэш-и-сеть, но это не решает основную проблему, заключающуюся в том, что операция (ваш запрос) не становится недействительной из-за мутации. Таким образом, повторная загрузка не будет выполняться.
Я очень рекомендую вам Graphcache, наш нормализованный кеш, который вы также уже обнаружили. Как минимум, без конфигурации (!), Это на самом деле простая замена, которая уже намного умнее. https://github.com/FormidableLabs/urql-exchange-graphcache
Конфигурация для него на самом деле просто дополнения, чтобы научить его, как обрабатывать больше задач автоматически! Я буду рад помочь вам в решении проблем здесь или через Spectrum, если вам нужно его настроить. Но я бы посоветовал попробовать, потому что в лучшем случае все ваши крайние случаи будут работать без каких-либо изменений ✨