Я использую стек Gatsby/Netlify CMS и пытаюсь отобразить содержимое файла уценки на главной странице. Например, у меня есть каталог в src/pages/experience, в котором отображаются все файлы уценки опыта.
Итак, используя graphql, у меня есть запрос, который действительно работает:
{
allMarkdownRemark(
limit: 3,
sort: { order: DESC, fields: [frontmatter___date] },
filter: { fileAbsolutePath: { regex: "/(experience)/" } }
) {
edges {
node {
id
frontmatter {
title
company_role
location
work_from
work_to
tags
}
excerpt
}
}
}
}
Однако при запуске на странице моего компонента отображается × TypeError: невозможно прочитать свойство allMarkdownRemark неопределенного
Однако после ввода этого перед возвратом:
if (!data) { return null };
Ошибка исчезает, но весь раздел исчезает. Вот оно ниже:
const Experience = ({data}) => {
return (
<div id = "experience" className = "section accent">
<div className = "w-container">
<div className = "section-title-group">
<Link to = "#experience"><h2 className = "section-heading centered">Experience</h2></Link>
</div>
<div className = "columns w-row">
{data.allMarkdownRemark.edges.map(({node}) => (
<div className = "column-2 w-col w-col-4 w-col-stack" key = {node.id}>
<div className = "text-block"><strong>{node.frontmatter.title}</strong></div>
<div className = "text-block-4">{node.frontmatter.company_role}</div>
<div className = "text-block-4">{node.frontmatter.location}</div>
<div className = "text-block-3">{node.frontmatter.work_from} – {node.frontmatter.work_to}</div>
<p className = "paragraph">{node.frontmatter.excerpt}</p>
<div className = "skill-div">{node.frontmatter.tags}</div>
</div>
))}
</div>
</div>
</div>
)}
export default Experience
В gatsby-config-js я добавил разрешение gatsby-source-filesystem отдельно от /src/posts в /src/pages, где каталог опыта — src/pages/experience.
Обновление: 07.02.2019 Вот файл gatsby-config-js:
module.exports = {
siteMetadata: {
title: `Howard Tibbs Portfolio`,
description: `This is a barebones template for my portfolio site`,
author: `Howard Tibbs III`,
createdAt: 2019
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
{
resolve: 'gatsby-transformer-remark',
options: {
plugins: [
{
resolve: 'gatsby-remark-images',
},
],
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `posts`,
path: `${__dirname}/src/posts`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `pages`,
path: `${__dirname}/src/pages`,
},
},
`gatsby-plugin-netlify-cms`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
},
},
`gatsby-transformer-sharp`
],
}
Я чувствую, что где-то в gatsby-node-js я не создал экземпляр, чтобы что-то делать с запросом этого типа.
const path = require('path')
const { createFilePath } = require('gatsby-source-filesystem')
const PostTemplate = path.resolve('./src/templates/post-template.js')
const BlogTemplate = path.resolve('./src/templates/blog-template.js')
exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions
if (node.internal.type === 'MarkdownRemark') {
const slug = createFilePath({ node, getNode, basePath: 'posts' })
createNodeField({
node,
name: 'slug',
value: slug,
})
}
}
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const result = await graphql(`
{
allMarkdownRemark (limit: 1000) {
edges {
node {
fields {
slug
}
}
}
}
}
`)
const posts = result.data.allMarkdownRemark.edges
posts.forEach(({ node: post }) => {
createPage({
path: `posts${post.fields.slug}`,
component: PostTemplate,
context: {
slug: post.fields.slug,
},
})
})
const postsPerPage = 2
const totalPages = Math.ceil(posts.length / postsPerPage)
Array.from({ length: totalPages }).forEach((_, index) => {
const currentPage = index + 1
const isFirstPage = index === 0
const isLastPage = currentPage === totalPages
createPage({
path: isFirstPage ? '/blog' : `/blog/${currentPage}`,
component: BlogTemplate,
context: {
limit: postsPerPage,
skip: index * postsPerPage,
isFirstPage,
isLastPage,
currentPage,
totalPages,
},
})
})
}
Хотел узнать, смог ли кто-нибудь получить что-то похожее на работу? Очень ценю вашу помощь.
Итак, я внес некоторые изменения в свой код с pageQuery на StaticQuery, и, к сожалению, он все еще не работает, но я считаю, что он движется в правильном направлении:
export default() => (
<div id = "experience" className = "section accent">
<div className = "w-container">
<div className = "section-title-group">
<Link to = "#experience"><h2 className = "section-heading centered">Experience</h2></Link>
</div>
<div className = "columns w-row">
<StaticQuery
query = {graphql`
query ExperienceQuery {
allMarkdownRemark(
limit: 2,
sort: { order: DESC, fields: [frontmatter___date]},
filter: {fileAbsolutePath: {regex: "/(experience)/"}}
) {
edges {
node {
id
frontmatter {
title
company_role
location
work_from
work_to
tags
}
excerpt
}
}
}
}
`}
render = {data => (
<div className = "column-2 w-col w-col-4 w-col-stack" key = {data.allMarkdownRemark.id}>
<div className = "text-block"><strong>{data.allMarkdownRemark.frontmatter.title}</strong></div>
<div className = "text-block-4">{data.allMarkdownRemark.frontmatter.company_role}</div>
<div className = "text-block-4">{data.allMarkdownRemark.frontmatter.location}</div>
<div className = "text-block-3">{data.allMarkdownRemark.frontmatter.work_from} – {data.allMarkdownRemark.frontmatter.work_to}</div>
<p className = "paragraph">{data.allMarkdownRemark.frontmatter.excerpt}</p>
<div className = "skill-div">{data.allMarkdownRemark.frontmatter.tags}</div>
</div>
)}
/>
</div>
</div>
</div>
);
Я получаю эту ошибку TypeError: Не удается прочитать заголовок свойства undefined
Итак, что я пытаюсь сделать, это этот экземпляр в этом разделе. Конечно, это заполнитель, но я хочу заменить этот заполнитель содержимым каждой уценки. Отрывок опыта
Итак, сегодня никаких изменений, но я хотел опубликовать несколько полей, чтобы лучше понять, что я пытаюсь сделать. Это файл config.yml из NetlifyCMS, в котором отображаются коллекции. Это то, что я выполняю (Примечание: тестовое репо предназначено только для того, чтобы увидеть фактическую CMS, я постараюсь изменить):
backend:
name: test-repo
branch: master
media_folder: static/images
public_folder: /images
display_url: https://gatsby-netlify-cms-example.netlify.com/
# This line should *not* be indented
publish_mode: editorial_workflow
collections:
- name: "experience"
label: "Experience"
folder: "experience"
create: true
fields:
- { name: "title", label: "Company Title", widget: "string" }
- { name: "company_role", label: "Position Title", widget: "string" }
- { name: "location", label: "Location", widget: "string" }
- { name: "work_from", label: "From", widget: "date", format: "MMM YYYY" }
- { name: "work_to", label: "To", default: "Present", widget: "date", format: "MMM YYYY" }
- { name: "description", label: "Description", widget: "text" }
- { name: "tags", label: "Skills Tags", widget: "select", multiple: "true",
options: ["ReactJS", "NodeJS", "HTML", "CSS", "Sass", "PHP", "Typescript", "Joomla", "CMS Made Simple"] }
- name: "blog"
label: "Blog"
folder: "blog"
create: true
slug: "{{year}}-{{month}}-{{day}}_{{slug}}"
fields:
- { name: path, label: Path }
- { label: "Image", name: "image", widget: "image" }
- { name: title, label: Title }
- { label: "Publish Date", name: "date", widget: "datetime" }
- {label: "Category", name: "category", widget: "string"}
- { name: "body", label: "body", widget: markdown }
- { name: tags, label: Tags, widget: list }
- name: "projects"
label: "Projects"
folder: "projects"
create: true
fields:
- { name: date, label: Date, widget: date }
- {label: "Category", name: "category", widget: "string"}
- { name: title, label: Title }
- { label: "Image", name: "image", widget: "image" }
- { label: "Description", name: "description", widget: "text" }
- { name: body, label: "Details", widget: markdown }
- { name: tags, label: Tags, widget: list}
- name: "about"
label: "About"
folder: "src/pages/about"
create: false
slug: "{{slug}}"
fields:
- {
label: "Content Type",
name: "contentType",
widget: "hidden",
default: "about",
}
- { label: "Path", name: "path", widget: "hidden", default: "/about" }
- { label: "Title", name: "title", widget: "string" }
- { label: "Body", name: "body", widget: "markdown" }
И для примера страницы уценки это будет формат, который нужно искать в разделе «Опыт», потому что, как вы видите на картинке, он отображается в контейнере:
---
title: Test Company
company_role: Test Role
location: Anytown, USA
work_from: January, 2020
work_to: January, 2020
tags: Test, Customer Service
---
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.
У меня есть некоторые обновления с кодом, представленным ниже, но прежде чем я приступлю к этому, вот несколько изображений того, что я хочу сделать. Это заполнители, которые я хочу заменить реальными данными. Это для каждого раздела:
Я запустил код, предоставленный @staypuftman в ответе ниже, и получил эту ошибку:
Your site's "gatsby-node.js" created a page with a component that doesn't exist.
Я добавил код в дополнение к тому, что уже было, и он обработал эту ошибку. Это то, что я изначально предполагал, и причина, по которой я хотел использовать StaticQuery независимо. На самом деле это была основная проблема, с которой я столкнулся при работе с документацией и начальными репозиториями: никто не создавал несколько переменных в node.js.
Я также попробовал версию @DerekNguyen, которая выглядела так:
import React from "react"
import { Link, graphql, StaticQuery } from "gatsby"
export default(data) => (
<div id = "experience" className = "section accent">
<div className = "w-container">
<div className = "section-title-group">
<Link to = "#experience"><h2 className = "section-heading centered">Experience</h2></Link>
</div>
<div className = "columns w-row">
<StaticQuery
query = {graphql`
query ExperienceQuery {
allMarkdownRemark(
limit: 2,
sort: { order: DESC, fields: [frontmatter___date]},
filter: {fileAbsolutePath: {regex: "/(experience)/"}}
) {
edges {
node {
id
frontmatter {
title
company_role
location
work_from
work_to
tags
}
excerpt
}
}
}
}
`}
render = {data.allMarkdownRemark.edges.map(({ node }) => (
<div className = "column-2 w-col w-col-4 w-col-stack" key = {node.id}>
<div className = "text-block"><strong>{node.frontmatter.title}</strong></div>
<div className = "text-block-4">{node.frontmatter.company_role}</div>
<div className = "text-block-4">{node.frontmatter.location}</div>
<div className = "text-block-3">{node.frontmatter.work_from} – {node.frontmatter.work_to}</div>
<p className = "paragraph">{node.frontmatter.excerpt}</p>
<div className = "skill-div">{node.frontmatter.tags}</div>
</div>
))}
/>
</div>
</div>
</div>
);
Однако это также привело к ошибке:
TypeError: Cannot read property 'edges' of undefined
Все еще работаю над этим, но я думаю, что он приближается к решению. Имейте в виду, что мне также пришлось бы создать его для других переменных.
Для тех, кто хочет увидеть, как я создал сайт с помощью gatsby-starter, вот он ниже:
Таким образом, компонент experience.js находится в другом каталоге. Это в src/components/Experience. У меня каждый раздел главной страницы разделен на подкомпоненты, и они идут в соответствующие каталоги. И затем, если мне нужно добавить определенную страницу в этот раздел, она переходит в этот каталог.
Тогда вы не сможете экспортировать запрос graphql и ожидать data в реквизитах, gatsby проигнорирует ваш запрос! Вместо этого вы должны использовать Статикзапрос
У меня StaticQuery закомментирован мой фактический код. Если это сработает, большое спасибо @DerekNguyen
Это не сработало для меня, я должен что-то упустить. Я буду поддерживать StaticQuery, но чего-то не хватает.
Не могли бы вы отредактировать ответ, чтобы добавить часть статического запроса?
Извините за это, был далеко от моего компьютера
Странно использовать Staticquery и gatsby-node.js вместе вот так. Если вы извлекаете данные с помощью gatsby-node.js, вы должны передать это компоненту и не нуждаться в дополнительных данных через Staticquery. Возможно, есть проблема с архитектурой, которую может решить улучшенная композиция компонентов.
Вы также должны опубликовать свою модель данных уценки, потому что ошибка, которую вы получаете, в основном означает, что Webpack говорит, что не может найти title в вашем файле уценки.
@staypuftman Мне еще предстоит подключить сторону NetlifyCMS, но я могу показать вам, что я ищу в коллекциях в config.yml. Я не уверен, где находится модель данных уценки, на которую вы ссылаетесь, но если вам нужен config.yml от Netlify, я мог бы опубликовать это. Из-за уценки, которая уже есть в моем каталоге, у каждого есть заголовок. Я опубликую один.
Я думаю, что в вашем запросе ошибка: fields: [frontmatter___date] без скобки на конце. Вы закрываете allMarkdownRemark, хотя этого делать не следует.
Я также добавил файл config.js. Я полагаю, что не понимаю, как получить данные из gatsby-node.js, поскольку я чувствовал, что как только вы создадите запрос из graphql, он сможет отобразить эту информацию. По сути, я не уверен, где бы я определил это в node.js.
@staypuftman Запрос, который у меня есть, находится в самом верху, и я быстро внесу изменения здесь. Сделайте пробел между скобками в полях: [frontmatter___date].
В вашем методе рендеринга StaticQuery вы обрабатываете allMarkdownRemark, как если бы это был узел. Это не так, вместо этого вам нужно будет сопоставить allMarkdownRemark.egdes, чтобы получить узел, то есть data.allMarkdownRemark.edges.map(({ node }) => (<div>...</div>)).
Я вижу, как я сделал это в начальном блоке, только вместо StaticQuery. Я проверю это.





gastby-node.js используется, когда у вас есть несколько страниц, которые должны находиться на /pages/{variable-here}/. Gatsby использует gatsby-node.js для выполнения запроса GraphQL к вашему источнику данных (в данном случае — Netlify CMS) и получает весь необходимый контент на основе вашего конкретного запроса GraphQL.
Затем он динамически создает X страниц, используя компонент вашего проекта. Сколько страниц он создает, зависит от того, что он находит в удаленном источнике данных. То, как они выглядят, зависит от указанного вами компонента. Подробнее об этом читайте в статье Гэтсби учебник.
Staticquery используется для получения одноразовых данных в компоненты, а не для генерации страниц из источника данных. Это очень полезно, но не то, что, я думаю, вы пытаетесь сделать. Подробнее об этом читайте на Сайт Гэтсби.
На основании всего этого и того, что вы предоставили выше, я думаю, что ваш gatsby-node.js должен выглядеть так:
// Give Node access to path
const path = require('path')
// Leverages node's createPages capabilities
exports.createPages = async ({ graphql, actions }) => {
// Destructures createPage from redux actions, you'll use this in a minute
const { createPage } = actions
// Make your query
const allExperiencePages = await graphql(`
{
allMarkdownRemark(limit: 1000) {
edges {
node {
id
frontmatter {
title
company_role
location
work_from
work_to
tags
}
excerpt
}
}
}
}
`)
// gatsby structures allExperiencePages into an object you can loop through
// The documentation isn't great but the 'data' property contains what you're looking for
// Run a forEach with a callback parameter that contains each page's data
allExperiencePages.data.allMarkdownRemark.edges.forEach( page => {
// Make individual pages with createPage variable you made earlier
// The 'path' needs to match where you want the pages to be when your site builds
// 'conponent' is what Gatsby will use to build the page
// 'context' is the data that the component will receive when you `gatsby build`
createPage({
path: `/pages/${page.node.title}/`,
component: path.resolve('src/components/Experience'),
context: {
id: page.node.id,
title: page.node.frontmatter.title,
company_role: page.node.frontmatter.company_role,
location: page.node.frontmatter.location,
work_from: page.node.frontmatter.work_from,
work_to: page.node.frontmatter.work_to,
tags: page.node.frontmatter.tags,
excerpt: page.node.excerpt
}
})
})
}
Одного этого может быть недостаточно для создания страницы! Все зависит от того, что происходит с компонентом, который вы указываете в компонентной части createPage файла gatsby-node.js.
Большое спасибо за этот ответ. Я попробую это со своей стороны. Я считаю, что избегал создания страниц для страниц уценки опыта. Я думал, что вы можете создавать экземпляры нужных вам полей в компоненте, не создавая страницу из этого конкретного файла. Я буду работать над этим и дам вам знать, что я получаю.
Кроме того, и именно по этой причине я делаю это, также будут страница проектов и страница блога, в каждом разделе которых будут отображаться 3 самых последних экземпляра на главной странице. С тем, что у вас есть выше, могу ли я создать константу для allProjects и allBlogs таким же образом?
Судя по вопросу ОП, похоже, что он хочет иметь независимый компонент Experience, который затем можно будет разместить внутри других страниц или шаблонов сообщений, а не создавать отдельные страницы опыта. @ Х.Тиббс, верно?
@DerekNguyen Правильно. Поэтому мне нужны эти компоненты для заполнения новых экземпляров: опыт, проекты и блоги. Каждый из них будет отображать 3 самых последних экземпляра (например, мой самый последний опыт, самые последние проекты и т. д.) на главной странице, но когда вы нажимаете на текст раздела или «Просмотреть больше» (думая добавить этот призыв к действию), он отобразит весь список этого компонента в порядке убывания. Например, страница блога, на которой перечислены все блоги, а затем щелкает каждый пост в блоге.
Кроме того, записи об опыте не обязательно должны быть отдельной публикацией, но для простоты это может быть тот же тип уценки.
Можете ли вы опубликовать визуальные эффекты того, как это будет выглядеть? Какие-либо страницы генерируются динамически?
@staypuftman Я опубликую несколько фотографий того, что я пытаюсь сделать выше в исходном вопросе. Проекты, Впечатления и Блоги будут генерироваться динамически, потому что каждый из них можно добавлять или удалять. Содержимое каждого раздела будет создаваться и поддерживаться через NetlifyCMS, где вы можете добавлять, редактировать или удалять их.
Но ключевой вопрос заключается в том, какие СТРАНИЦЫ будут динамически генерироваться. Вы динамически генерируете страницы в gatsby-node.js. Динамически генерируемые РАЗДЕЛЫ происходят с помощью «Статического запроса» на статических страницах.
Я считаю, что пытался динамически генерировать разделы. Таким образом, переосмыслив это, нужно будет создавать страницы, потому что каждая страница или уценка будут иметь уникальное свойство. Так что каждый опыт будет другим, каждый проект будет другим, каждый блог будет другим. Извините за путаницу.
Я думаю, вам нужно сочетание обеих динамических страниц с динамически генерируемыми разделами. Таким образом, у вас будут динамически сгенерированные страницы, как я сделал выше, а затем внутри компонента, на который вы ссылаетесь, внутри createPage, куда пойдет статический запрос. Дайте мне знать, если это имеет смысл.
Я покажу внутреннюю часть песочницы кода, чтобы показать вам, как она устроена. Может быть, это даст лучшее представление о том, к чему я стремлюсь. Но, как я уже упоминал о node.js, я считаю, что именно здесь код должен быть первым, прежде чем он будет передан компонентам, и именно в этом заключается сложность.
Где этот компонент Experience находится в вашем src? Может быть, вы используете страничный запрос в нестраничном компоненте?