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