Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
130 views
in Technique[技术] by (71.8m points)

javascript - gatsby.js: "node.frontmatter.image is null"

LAST EDIT: fixed. It was a naming convention. I am currently using this tree structure:

-pages --posts ---00X-post For pagination/programmatically works fine so far. And inside, md with its correspondent image (used as a thumbnail too). One of those had the naming wrong. Fixed. Now everything is working just fine.

EDIT and UPDATE:

Thank you for your quick answer. I tried that, nothing changed. I do believe it has to do with all the templates for pagination I am currently using. For example, the one in charge of creating page 2 and so in is this one:

import React from 'react';
import Layout from '../components/layout';
import Post from '../components/Post';
import { graphql } from 'gatsby';
import { Row, Col } from 'reactstrap'; 
import Sidebar from '../components/Sidebar'; 
import PaginationLinks from '../components/PaginationLinks'; 

const postList = (props) => {
    const posts = props.data.allMarkdownRemark.edges
    const { currentPage, numberOfPages } = props.pageContext 

    return (
        <Layout pageTitle>
        <h1 className='titles'>{`page ${currentPage}`}</h1>
            <Row>
                <Col>
                {posts.map(({node}) => (
                    <Post
                        key={node.id}
                        slug={node.fields.slug}
                        title={node.frontmatter.title}
                        author={node.frontmatter.author}
                        date={node.frontmatter.date}
                        body={node.excerpt}
                        tags={node.frontmatter.tags}
                        fluid={node.frontmatter.image.childImageSharp.fluid}
                    />
                ))}
                <PaginationLinks 
                currentPage={currentPage} 
                numberOfPages={numberOfPages} 
                    
                />
                </Col>
                <Col md='4'>
                    <Sidebar>

                    </Sidebar>
                </Col>
            </Row>
        </Layout>
    )

}

export const postListQuery = graphql`
    query postListQuery($skip: Int!, $limit: Int!) {
        allMarkdownRemark(
            sort: { fields: [frontmatter___date], order: DESC}
            limit: $limit
            skip: $skip 
        ) {
            edges {
                node {
                    id 
                    frontmatter {
                        title
                        date
                        author
                        tags
                        image {
                            childImageSharp {
                                fluid(maxWidth: 650, quality: 90) {
                                    ...GatsbyImageSharpFluid
                                }
                            }
                        }
                    }
                    fields {
                        slug
                    }
                    excerpt
                }
            }
        }
    }
`

export default postList

Same error messages appear when creating pages by tags/authors. If I delete the image field from the query, everything works. This is unusual.

While doing a simple blog project with Gatsby I run into either "TypeError: childImageSharp is undefined” or "node.frontmatter.image is null". This error message appears at random. By the time I started writing this, trying to access pages/2 only triggered it.

Here's index.js:

import React from "react"
import { graphql, StaticQuery } from 'gatsby'; 

import Layout from "../components/layout"
import SEO from "../components/seo"
import Post from '../components/Post'; 
import Sidebar from '../components/Sidebar'; 
import { Row, Col } from 'reactstrap'; 
import PaginationLinks from '../components/PaginationLinks'; 

const IndexPage = () => {

  const postsPerPage = 5; 
  let numberOfPages 

  return (
    <Layout>
    <SEO title="home" keywords={[`procedural`, `gatsby`]}/>
    <h1 className='titles'>procedural</h1>

    <Row>
      <Col>
        <StaticQuery 
        query={indexQuery}
        render={data => {

          numberOfPages = Math.ceil(
          data.allMarkdownRemark.totalCount / postsPerPage
          ); 

          return (
            <div>
              {
                data.allMarkdownRemark.edges.map(({ node }) => (
                  <Post 
                  key={node.id}
                  title={node.frontmatter.title}
                  author={node.frontmatter.author}
                  date={node.frontmatter.date}
                  slug={node.fields.slug}
                  body={node.excerpt}
                  fluid={node.frontmatter.image.childImageSharp.fluid}
                  tags={node.frontmatter.tags}
                  /> 
                ))
              }
              <PaginationLinks currentPage={1} numberOfPages={numberOfPages} />
            </div>
          )
        }}
        />
      </Col>
      <Col md='4'>
        <Sidebar>

        </Sidebar>
      </Col>
    </Row>

    </Layout>
  )
}

const indexQuery = graphql`
query {
  allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC}
    limit: 5
    ) {
    totalCount
    edges {
      node {
        id
        frontmatter {
          title
          date
          author
          tags
          image {
            childImageSharp {
              fluid(quality: 85, maxWidth: 960) {
                ...GatsbyImageSharpFluid
              }
            }
          }
        }
        fields {
          slug
        }
        excerpt
      }
    }
  }
}
`

export default IndexPage

Here's gatsby-node.js:

const path = require('path'); 
const { slugify } = require('./src/utils/utilityFunctions');
const authors = require('./src/utils/authors'); 
const _ = require('lodash'); 

// single post generator
exports.onCreateNode = ({ node, actions }) => {
    const { createNodeField } = actions
    if(node.internal.type === 'MarkdownRemark') {
        const slugFromTitle = slugify(node.frontmatter.title)
        createNodeField({
            node, 
            name: 'slug',
            value: slugFromTitle,
        })
    }
}

exports.createPages = async ({ actions, graphql }) => {
    const { createPage } = actions; 
    
    
    const templates = {
        singlePost: path.resolve('./src/templates/single-post.js'),
        tagsPage: path.resolve('./src/templates/tags-page.js'),
        tagPosts: path.resolve('./src/templates/tag-post.js'),
        postList: path.resolve('./src/templates/post-list.js'),
        authorPosts: path.resolve('./src/templates/author-posts.js'), 
    } 

    const res = await graphql(`
        {
            allMarkdownRemark {
                edges {
                    node {
                        frontmatter{
                            author
                            tags
                        }
                        fields {
                            slug
                        }
                    }
                }
            }
        }
    `)
    
    if(res.errors) return Promise.reject(res.errors)

    const posts = res.data.allMarkdownRemark.edges

    posts.forEach(({node}) => {
        createPage({
            path: node.fields.slug,
            component: templates.singlePost,
            context: {
                // passing slug, PENDING TAGS
                slug: node.fields.slug,
                // finding author imageUrl from authors.js and passing it to the single post template 

            },
        })
    })


            // creating post pages

    const postsPerPage = 5
    const numberOfPages = Math.ceil(posts.length / postsPerPage)

    Array.from({ length: numberOfPages }).forEach((_, index) => {
        const isFirstPage = index === 0
        const currentPage = index + 1

        // skip first page and go to index.js
        if (isFirstPage) return

        createPage({
            path: `/page/${currentPage}`,
            component: templates.postList,
            context: {
                limit: postsPerPage,
                skip: index * postsPerPage,
                numberOfPages: numberOfPages,
                currentPage: currentPage,
            },
            })
        })

        // tags PAGE GENERATOR; getting all tags
        let tags = []
        _.each(posts, edge => {
            if (_.get(edge, 'node.frontmatter.tags')) {
              tags = tags.concat(edge.node.frontmatter.tags)
            }
          })

        // account of tags, we're putting them like this: ['design', 'example', 'luck'] and also {design: X, example: Y, luck: z}
        let tagPostCounts = {}
        tags.forEach(tag => {
            tagPostCounts[tag] = (tagPostCounts[tag] || 0) + 1; 
        })

        tags = _.uniq(tags) //elimninate all duplicate entries 

        // create tags page here 
        createPage({
            path: `/tags`,
            component: templates.tagsPage,
            context: {
                tags,
                tagPostCounts,
            }
        })

        // tag post page creation here: 
        tags.forEach(tag => {
            createPage({
                path: `/tag/${_.kebabCase(tag)}`,
                component: templates.tagPosts,
                context: {
                    tag
                }
            })
        })

        // CREATING PAGES FOR EACH AUTHOR'S POSTS: 
        authors.forEach(author => {
            createPage({
                path: `/author/${slugify(author.name)}`,
                component: templates.authorPosts,
                context: {
                    authorName: author.name,
                    imageUrl: author.imageUrl, 
                }, 
            })
        })
}

here's gatsby-config.js:

  plugins: [
    `gatsby-plugin-sharp`,
    `gatsby-transformer-sharp`,
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-sass`,
    `gatsby-transformer-remark`,
    `gatsby-plugin-catch-links`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/pages`,
      },
    },
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `procedural`,
        short_name: `procedural`,
        start_url: `/`,
        background_color: `#663399`, // PLACEHOLDER
        theme_color: `#663399`, // PLACEHOLDER
        display: `minimal-ui`, // PLACEHOLDER
        icon: `src/images/logo.png`, // This path is relative to the root of the site.
      },
    },
  ],

And here's my single-post.js:

import React from 'react';
import Layout from '../components/layout'; 
import { graphql, Link } from 'gatsby'; 
import SEO from '../components/seo';
import { Badge, Card, CardBody, CardSubtitle } from 'reactstrap'; 
import Img from 'gatsby-image'; 
import { slugify } from '../utils/utilityFunctions'; 

const SinglePost = ({ data, pageContext }) => {
    const post = data.markdownRemark.frontmatter; 

    return (
        <Layout>
            <SEO title={post.title}/>
            <h1 className='postTitles'>{post.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You are using a page query in your IndexPage component, however, you are retrieving the data using a StaticQuery component. Change it to:

import React from "react"
import { graphql, StaticQuery } from 'gatsby'; 

import Layout from "../components/layout"
import SEO from "../components/seo"
import Post from '../components/Post'; 
import Sidebar from '../components/Sidebar'; 
import { Row, Col } from 'reactstrap'; 
import PaginationLinks from '../components/PaginationLinks'; 

const IndexPage = ({data}) => {

  const postsPerPage = 5; 
  let numberOfPages 

  return (
    <Layout>
    <SEO title="home" keywords={[`procedural`, `gatsby`]}/>
    <h1 className='titles'>procedural</h1>

    <Row>
      <Col>
            <div>
              {
                data.allMarkdownRemark.edges.map(({ node }) => (
                 {node.frontmatter.image && <Post 
                  key={node.id}
                  title={node.frontmatter.title}
                  author={node.frontmatter.author}
                  date={node.frontmatter.date}
                  slug={node.fields.slug}
                  body={node.excerpt}
                  fluid={node.frontmatter.image.childImageSharp.fluid}
                  tags={node.frontmatter.tags}
                  /> }
                ))
              }
              <PaginationLinks currentPage={1} numberOfPages={numberOfPages} />
            </div>
      </Col>
      <Col md='4'>
        <Sidebar>

        </Sidebar>
      </Col>
    </Row>

    </Layout>
  )
}

const indexQuery = graphql`
query {
  allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC}
    limit: 5
    ) {
    totalCount
    edges {
      node {
        id
        frontmatter {
          title
          date
          author
          tags
          image {
            childImageSharp {
              fluid(quality: 85, maxWidth: 960) {
                ...GatsbyImageSharpFluid
              }
            }
          }
        }
        fields {
          slug
        }
        excerpt
      }
    }
  }
}
`

export default IndexPage

The data fetched using pages queries, is stored under props. Since in the snippet above you are destructuring props as data (({data})), you don't need to trigger another query like you were doing, your data is already stored in data. So you can loop it in the same way you were doing.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...