Я использую стек 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, вот он ниже:
🤔 А знаете ли вы, что...
React имеет строгую систему типов с использованием TypeScript или Flow.
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
.