我在我的项目上使用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接口上运行这些确切的查询,则一切运行正常:
关于我在哪里失败的任何想法?
答案 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
},
})
由于您在查询中将其用作不可为空的skip
和limit
变量(标有感叹号!
)在这里:
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
。
可能出现两种循环情况:
第一个选项很简单,但可能会占用大数据集的资源,它有时可能会崩溃。
第二个(更好的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