Как мне обновить кеш 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, если вам нужно его настроить. Но я бы посоветовал попробовать, потому что в лучшем случае все ваши крайние случаи будут работать без каких-либо изменений ✨

Другие вопросы по тегам