我无法使用盖茨比动态创建页面

时间:2020-07-02 15:43:03

标签: javascript reactjs ecmascript-6 graphql gatsby

我在我的项目上使用Gatsby。我正在尝试创建一个需要分页的页面。

我遵循了此https://www.gatsbyjs.org/docs/adding-pagination/和另一本指南https://nickymeuleman.netlify.app/blog/gatsby-pagination/以及操作方法,但是没有用。

我在gatsby-node.js上有多个查询:

exports.createPages = async ({ graphql, actions, page }) => {
    const { createPage } = actions
    const shop = path.resolve("./src/templates/shop.js")
    const productPageTemplate = path.resolve("./src/templates/ProductPage/index.js")
    
    const singleProduct = await graphql(`
      query {
        allShopifyProduct {
          edges {
            node {
              handle
            }
          }
        }
      }
    `)
    
    // This is the query which I need for the pagination
    // Create shop pages
    const products = await graphql(`
      query allShopifyProduct($skip: Int!, $limit: Int!) {
        allShopifyProduct(sort: { fields: [createdAt], order: DESC }
          skip: $skip
          limit: 5
        ) {
          edges {
            node {
              id
              title
              handle
            }
          }
        }
      }
    `)
    
    const posts = products.data.allShopifyProduct.edges  
    
    const postsPerPage = 5
    const numPages = Math.ceil(posts.length / postsPerPage)
    
    Array.from({ length: numPages }).forEach((_, i) => {
      const withPrefix = (pageNumber) =>
        pageNumber === 1 ? `/shop` : `/shop/${pageNumber}`
      const pageNumber = i + 1
      createPage({
        path: withPrefix(pageNumber),
        component: shop,
        context: {
          limit: postsPerPage,
          skip: i * postsPerPage,
          current: pageNumber,
          total: numPages,
          hasNext: pageNumber < numPages,
          nextPath: withPrefix(pageNumber + 1),
          hasPrev: i > 0,
          prevPath: withPrefix(pageNumber - 1),
        },
      })
    })
    
    // Adding the single product stuff to show my multiple queries
    singleProduct.data.allShopifyProduct.edges.forEach(({ node }) => {
      createPage({
        path: `/product/${node.handle}/`,
        component: productPageTemplate,
        context: {
          // Data passed to context is available
          // in page queries as GraphQL variables.
          handle: node.handle,
        },
      })
    })
})

这是我的React组件:

import React from "react"
import { graphql, Link } from "gatsby"

// Components
import ProductGrid from "@components/ProductGrid/productGrid"

const Shop = ({ data: { allShopifyProduct }, pageContext }) => {
  return (
    <div className="product-grid">
      <ProductGrid allShopifyProduct={allShopifyProduct}
      />
      {!pageContext.hasPrev && (
        <Link to={pageContext.prevPage} rel="prev">
          ← Previous Page
        </Link>
      )}
      {!pageContext.hasNext && (
        <Link to={pageContext.nextPage} rel="next">
          Next Page →
        </Link>
      )}
    </div>
  )
}

export default Shop

export const query = graphql`
  query allShopifyProduct($skip: Int!, $limit: Int!) {
    allShopifyProduct(
      sort: { fields: [createdAt], order: DESC }
      skip: $skip
      limit: $limit
    ) {
      edges {
        node {
          id
          title
          handle
        }
      }
    }
  }
`

并且不断抛出以下错误:

 ERROR #85927  GRAPHQL

There was an error in your GraphQL query:

Variable "$skip" is never used in operation "allShopifyProduct".

See if $skip has a typo or allShopifyProduct doesn't actually require this variable.

File: gatsby-node.js:74:26


 ERROR #85927  GRAPHQL

There was an error in your GraphQL query:

Variable "$limit" is never used in operation "allShopifyProduct".

See if $limit has a typo or allShopifyProduct doesn't actually require this variable.

File: gatsby-node.js:74:26


 ERROR #11321  PLUGIN

"gatsby-node.js" threw an error while running the createPages lifecycle:

Cannot read property 'allShopifyProduct' of undefined

  108 |   `)
  109 |
> 110 |   const posts = products.data.allShopifyProduct.edges
      |                               ^
  111 |

File: gatsby-node.js:110:31



  TypeError: Cannot read property 'allShopifyProduct' of undefined

  - gatsby-node.js:110 Object.exports.createPages
    /Users/marcelo/Work/gatsby-on-demand/gatsby-node.js:110:31

failed createPages - 0.113s

如果我在GraphiQL接口上运行这些确切的查询,则一切运行正常: enter image description here

关于我在哪里失败的任何想法?

2 个答案:

答案 0 :(得分:2)

您必须在createPage API的上下文中提供这些变量:

  createPage({
    path: `/product/${node.handle}/`,
    component: productPageTemplate,
    context: {
      skip: 0 // or any variable
      limit: 5 // or any variable
      handle: node.handle, // is it used? If don't, you can remove it
    },
  })

由于您在查询中将其用作不可为空的skiplimit变量(标有感叹号!)在这里:

  query allShopifyProduct($skip: Int!, $limit: Int!)

它们必须存在,因此您需要(通过上下文)以与出现在GraphQL查询游乐场中相同的方式提供它们。

您的handle变量似乎未使用,至少在提供的代码中未使用,在这种情况下,您可以将其删除。

有关GraphQL Schema and Types的更多信息。

答案 1 :(得分:1)

在一开始...用于将查询中使用的参数/值(作为变量)传递的方法...您应将其(值)传递给“循环”查询中的变量:

let myLoopingSkip = 0; // starting skip

// Create shop pages
const products = await graphql(`
  query allShopifyProduct($skip: Int!, $limit: Int!) {
    allShopifyProduct(sort: { fields: [createdAt], order: DESC }
      skip: $skip
      limit: $limit
    ) {
      edges {
        node {
          id
          title
          handle
        }
      }
    }
  }
`,  { skip: myLoopingSkip, limit: 5 } ); // variables used in query

然后,您可以在整个块(用于分页列表和单个产品的query + createPages)块上构建“外部”循环,将当前myLoopingSkip的值传递给查询变量skip

可能出现两种循环情况

  • 一次查询所有产品(所有数据);
  • 仅查询当前迭代所需的数据段(5项记录集/块)。

第一个选项很简单,但可能会占用大数据集的资源,它有时可能会崩溃。

第二个(更好的IMHO)选项更加可靠,但是在循环之前需要对numPages(所有产品的数量)进行附加/单独的查询。条件next page也需要它。

在现实生活中,浏览10页后并不常见...实际上,即使是Google在某个页面限制后也会停止显示结果...但是产品页面必须链接到某个地方才能访问/抓取-恕我直言,最好分页短按类别列出。

如果您确实不需要numPages,只要查询的数据(结果)包含5条记录,就可以简单地通过添加5(您的'limit'/ postsPerPage)来保持循环。在这种情况下,“外循环”如下所示:

const postsPerPage = 5;
let myLoopingSkip = 0; // starting skip
do {
  // read only data you need in current iteration
  let products = await graphql(PAGINATED_PRODUCTS_QUERY, 
    { skip: myLoopingSkip, limit: postsPerPage } );

  // paginated list
  createPage({
    path: withPrefix(pageNumber),
    component: shop,
    context: {
      limit: postsPerPage,
      skip: i * postsPerPage,
    ...      
  // but you can just pass fetched data
  // as is done for product page
  // no need for query inside component
  // just loop over `data` prop to create grid view
  //
  // createPage({
  //   path: withPrefix(pageNumber),
  //   component: shop,
  //   context: {
  //     data: products.data.allShopifyProduct.edges,

  // loop for single products pages
  products.data.allShopifyProduct.edges.map( (node) => {
    createPage({
    path: `/product/${node.handle}/`,
    component: productPageTemplate,
    context: {
      // Data passed to context is available
      // in page queries as GraphQL variables.
      handle: node.handle,
      // ... but we already have all data here 
      // ... again, no query needed
      // data: node
    }
  });

  myLoopingSkip += postsPerPage;
} while( products.data.allShopifyProduct.edges.length===postsPerPage )
// or use total page condition