#graphql #graphql-js #relayjs #relay
Вопрос:
Контекст
Эта проблема, скорее всего, связана с определенным выбором, некоторые из которых можно изменить, а некоторые-нет. Мы используем следующие технологии и структуры:
- Ретрансляция / Реакция / МашиНопись
- Контент-стек (CMS)
Проблема
Я пытаюсь создать настраиваемую страницу, которую можно создавать из нескольких типов компонентов пользовательского интерфейса на основе представленных данных (чтобы страницы можно было создавать с помощью CMS, используя сборный пользовательский интерфейс в непредсказуемом порядке).
Моей первой попыткой в этом было создать набор фрагментов для потенциальных компонентов пользовательского интерфейса, на которые можно ссылаться в массиве:
query CustomPageQuery {
title
description
customContentConnection {
edges {
node {
... HeroFragment
... TweetBlockFragment
... EmbeddedVideoFragment
"""
Further fragments are added here as we add more kinds of UI
"""
}
}
}
}
В используемой нами CMS (ContentStack) сложность этого запроса возросла до такой степени, что он отклоняется, поскольку требует слишком большого количества вызовов базы данных в одном запросе. По этой причине я надеюсь, что есть способ разделить вызовы для фрагментов так, чтобы они не были частью первоначального запроса, или какое-то аналогичное решение, которое приведет к разделению этого запроса на несколько частей.
Я надеялся @defer
, что директива решит эту проблему для меня, но она не поддерживается relay-compiler
.
Есть какие-нибудь идеи?
Ответ №1:
К сожалению @defer
, это все еще не стандарт, поэтому он не поддерживается большинством реализаций (поскольку для его поддержки вам также понадобится сервер).
Я не уверен, правильно ли я понимаю проблему, но вы, возможно, захотите больше сосредоточиться на использовании @skip
или @include
только на извлечении нужного вам фрагмента в зависимости от типа вещи. Но для этого потребуется, чтобы интерфейс заранее знал, что он хочет запросить.
query CustomPageQuery($hero: Boolean, $tweet: Boolean, $video: Boolean) {
title
description
customContentConnection {
edges {
node {
... HeroFragment @include(if: $hero)
... TweetBlockFragment @include(if: $tweet)
... EmbeddedVideoFragment @include(if: $video)
}
}
}
}
Как правило, вы хотите иметь возможность различать тип без необходимости выполнять запрос к базе данных. Так сказать:
type Hero {
id: ID
name: String
}
type Tweet {
id: ID
content: String
}
union Content = Hero | Tweet
{
Content: {
__resolveType: (parent, ctx) => {
// That should be able to resolve the type without a DB query
},
}
}
Как только это будет передано, каждый фрагмент затем будет разрешен, что приведет к большему количеству запросов к базе данных. Если они неправильно упакованы с загрузчиками данных, то у вас проблема N 1. Я не уверен, насколько сильно вы контролируете (если вообще контролируете) серверную часть, но для вашей проблемы нет серебряной пули.
Если вы не можете оптимизировать серверную часть, я бы посоветовал попытаться ограничить подключение. Похоже, они используют разбиение на страницы на основе курсора, поэтому вы начинаете с say first: 10
, и как только будет возвращена первая партия, вы можете запросить следующие элементы, установив значение after
на последний курсор предыдущей партии:
query CustomPageQuery($after: String) {
customContentConnection(first: 10, after: $after) {
edges {
cursor
node {
... HeroFragment
... TweetBlockFragment
... EmbeddedVideoFragment
}
}
pageInfo {
hasNextPage
}
}
}
В крайнем случае, вы можете попытаться сначала получить все идентификаторы, а затем выполнить последующие запросы к CMS для каждого идентификатора (я думаю, используя псевдонимы) или типа (если вы можете фильтровать поле подключения). Но я чувствую себя грязным, просто пишу это, так что избегайте этого, если можете.
{
one: node(id: "UUID1") {
... HeroFragment
... TweetBlockFragment
... EmbeddedVideoFragment
}
two: node(id: "UUID2") {
... HeroFragment
... TweetBlockFragment
... EmbeddedVideoFragment
}
}
Комментарии:
1. Хм, хорошая информация здесь. Я не уверен, что это действительно помогает моему делу, но я ценю это! Я буду копать дальше.