Проблема с доступом к API Contentful с помощью хелпера getEntry(): из обещания найденной записи не возвращается контент

вступление

Несколько дней назад я разместил здесь вопрос с просьбой о помощи с контентным API для javascript-запроса объектов, и с тех пор я изо всех сил пытался понять одну вещь об использовании этого API с NextJS.

Дело в том, что пакет contentful предоставляет два помощника: getEntries() и getEntry(). Первый действительно помог мне получить контент для страницы, над которой я работаю, но я чувствую, что из-за структуры модели контента у меня возникают проблемы с доступом к связанным записям на этой странице.

Рабочий код

Я установил contentfulClient в отдельный файл, но для объяснения позвольте мне объединить оба:

import Head from 'next/head'

// ./lib/contentful-client.js
const { createClient } = require('contentful')

const contentfulClient = createClient({
  space: process.env.NEXT_PUBLIC_CONTENTFUL_SPACE,
  accessToken: process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN
})

module.exports = contentfulClient

// ./pages/index.js
export async function getStaticProps() {
  let data = await contenfulClient.getEntries({
    content_type: 'page',
    'field.slug': 'page_slug'   // <-- this is being manually set for each page
  })
  return {
    props: {
      pagina: data.items[0]     // <-- where the props are build and exported
    }
  }
}

export default function HomePage({ pagina }) {

  const { title, slug, sections } = pagina.fields

  return (
    <div>
      <Head>
        <title>{title}</title>
      </Head>
      <main id = {slug}>
        {sections.map((section) => {
          console.info(section)
        })}
      </main>
    </div>
  )
}

Это будет извлекать содержимое для каждого раздела, из которого построена страница. Консоль отображает лог фактической структуры до некоторого уровня, и вот в чем подвох.

Структура модели контента

Фактическая модель содержимого для страниц была разработана для обеспечения гибкости для пользователя, который может выбрать либо предоставить вложение изображения для раздела, либо нет, либо создать другой компонент с другими свойствами.

├── Page
|     ├── title
|     ├── slug
|     └── section
|           ├── title
|           ├── slug
|           ├── content
|           └── components
|                 ├── imageComponent
|                 ├── formComponent
|                 └── extraComponent
.                     .
.                     .
.                     .

С помощью предыдущей функции getStaticProps() код, отображающий разделы, может получить доступ к этому массиву компонентов, но не вернет его содержимое:

// console output
{sys: {…}, fields: {…}}
  fields:
    componentes: Array(3)
      0:
        sys: {type: "Link", linkType: "Entry", id: "X1n2uZJfMMwtJbY3H7Z6M"}
        __proto__: Object
        1:
        sys: {type: "Link", linkType: "Entry", id: "19gYv80phM75jgmAKCgwAI"}
        __proto__: Object
        2:
        sys: {type: "Link", linkType: "Entry", id: "4xCKnCVG142Mxl9s1iNsPZ"}
        __proto__: Object
        length: 3
        __proto__: Array(0)

Итак, чтобы сделать это, я понял, что getEntry(<entry_id>) будет хорошим способом добраться до этого контента, возможно, каким-то образом превратить его в структуру json.

// ./pages/index.js
return (
    <div>
      <Head>
        <title>{title}</title>
        <link rel = "icon" href = "/favicon.ico" />
      </Head>
      <main id = {slug}>
        {secoes.map((secao) => {
          contentfulClient.getEntry(secao.sys.id)
            .then((entry) => console.info(entry))
            .catch((err) => console.error(err))
        })}

      </main>
      <footer >
        (footer)
      </footer>
    </div>
  )

// console output
{sys: {…}, fields: {…}, toPlainObject: ƒ}
  fields:
    slug: "hero"
    title: "This is my title!"
    components: Array(3)
      0:
        fields:
          main: Array(2)
            0:
              fields:
                file:
                  contentType: "image/png"
                  details: {size: 188420, image: {…}}
                  fileName: "bkgHero.png"
                  url: "<path_to>/bkgHero.png" // <-- can reach the paths for images, for instance. 
                  __proto__: Object
                title: "heroBkg"
                __proto__: Object
              sys:
                createdAt: "2020-06-08T15:18:42.394Z"
                environment: {sys: {…}}
                id: "5E2h7vNFAFTW4BYKWPJo9E"
                locale: "pt-BR"
                revision: 3
                space: {sys: {…}}
                type: "Asset"
                updatedAt: "2020-06-30T19:05:51.537Z"
                __proto__: Object
              __proto__: Object

"сломанный" код

Ну, он не совсем сломан. Он регистрируется, и я могу видеть весь контент этих объектов, но я не могу понять это, так как обещание .then() не вернет значение, которое я могу использовать на своей странице.

// ./pages/index.js
    return (
        <div>
          <Head>
            <title>{title}</title>
            <link rel = "icon" href = "/favicon.ico" />
          </Head>
          <main id = {slug}>
            {secoes.map((secao) => {
              contentfulClient.getEntry(secao.sys.id)
                .then((entry) => <span>{entry.fields.slug}</span>) // <-- Trying to fetch content from that entry
                .catch((err) => console.error(err))
            })}
    
          </main>
          <footer >
            (footer)
          </footer>
        </div>
      )

Из консоли не возвращается ошибка, и моя структура страницы не будет отображать диапазон с этим слагом:

<div id = "__next">
  <div>
    <main id = "index"></main>
    <footer>(footer)</footer>
  </div>
</div>

Это ответ на вопрос здесь , говорящий, что getEntry() - это правильный способ получить доступ к этому контенту, и я очень старался с этим методом, но безуспешно. Другие говорят запрашивать с getEntries() и тоже пробовали, но безуспешно.

Я считаю, что основная проблема здесь заключается в том, что NextJS заставляет меня извлекать это содержимое в индексе, чтобы передавать реквизиты компонентам моей страницы, и теоретически это должно работать в обоих направлениях, потому что оба способа вернут мне содержимое в журнал. Я просто не могу связаться с ним как с реквизитом или в цепочке данных.

Не знаю, как действовать. Должен ли я переосмыслить все это по-другому или даже попробовать GraphQL API? Никогда не использовал это за пределами Гэтсби, и даже в этом я не эксперт. Буду признателен за любые мысли по этому поводу и предложения о том, как действовать.

🤔 А знаете ли вы, что...
JavaScript поддерживает модульную структуру, что способствует организации кода на больших проектах.


1
1 230
1

Ответ:

Решено

Контент DevRel здесь. 👋

Глядя на код и то, как вы подошли к использованию getStaticProps, мне кажется, что это правильный путь, имхо.

Чтобы получить доступ к ссылкам более чем на один уровень ниже во вложенности, вы должны определить параметр включения запроса. include по умолчанию имеет значение 1, что объясняет, почему вы можете получить доступ к sections, но не к содержимому components. При работе с вложенными структурами содержимого рекомендуется увеличить количество включенных уровней вложенности.

// ./pages/index.js
export async function getStaticProps() {
  let data = await contenfulClient.getEntries({
    content_type: 'page',
    'field.slug': 'page_slug'
    include: 5 // <-- this defaults to 1
  })
  return {
    props: {
      pagina: data.items[0]
    }
  }
}