Reputation: 411
I've created a blog in my first GatsbyJS project, I'm very new to React and Gatsby
The blog itself is working perfectly, I'm pulling in the content through markdown files, but I'm struggling a lot to get the pagination part working.
I have 4 pages blogTemplate (a template for each individual blog post), posts.js (loops through and displays each of the blog posts on a single landing page), blog.js (pulls in all the blog post in an array from the posts page and displays them in cards) and my gatsby-node.js page (which is handling the graphql for the blogs)
Below is a list of all of the files I am usings and at the bottom is some of the plugins I have tried to implement
blogTemplate.js
import React from "react";
import { graphql, Link } from "gatsby";
import { Container, Row, Col, Image } from "react-bootstrap";
import Layout from "../components/layout";
export default function Template({ data }) {
const post = data.markdownRemark;
const { markdownRemark } = data // data.markdownRemark holds your post data
const { frontmatter, html } = markdownRemark
const { title, author, date, thumbnail } = post.frontmatter;
return (
<Layout>
<Container className="px-0" >
<Row>
<Col>
<Container className="mt-5 mb-5">
<h1>{title}</h1>
<p>Posted by {author} on {date} thumbnail {thumbnail}</p>
<Image src={thumbnail} alt={thumbnail} fluid />
<div dangerouslySetInnerHTML={{ __html: post.html }} />
<Link to="/blog">Back to blogs</Link>
</Container>
</Col>
</Row>
</Container>
</Layout>
)
};
export const postQuery = graphql`
query BlogPost($path: String!) {
markdownRemark(frontmatter: { path: { eq: $path }}) {
html
frontmatter {
author
date
title
path
description
thumbnail
}
html
}
}
`;
Posts.js
import React from "react"
import { Link } from "gatsby"
import { Card } from 'react-bootstrap';
const PostLink = ({ post }) => (
<Card className="cardpadding">
<Card.Img variant="top" src={post.frontmatter.thumbnail} alt={post.frontmatter.title} />
<Card.Body className="dark-text">
<p>{post.frontmatter.date}</p>
<Card.Title>{post.frontmatter.title}</Card.Title>
<Card.Text className="blue-text">
<Link to={post.frontmatter.path} className="post-link">
{post.frontmatter.title}
</Link>
</Card.Text>
</Card.Body>
</Card>
)
export default PostLink
blog.js
import React from "react"
import { graphql } from "gatsby"
import Post from "../components/post";
import Layout from "../components/layout"
import { Container } from "react-bootstrap";
const BlogPage = ({
data: {
allMarkdownRemark: { edges },
},
}) => {
const Posts = edges
.filter(edge => !!edge.node.frontmatter.date) // You can filter your posts based on some criteria
.map(edge => <Post key={edge.node.id} post={edge.node} />)
console.log('Posts', Posts)
return (
<Layout>
<Container className="mt-5">
<div className="grids">
{Posts}
</div>
</Container>
</Layout>
)
}
export default BlogPage
export const AllBlogsQuery = graphql`
query AllBlogPosts {
allMarkdownRemark(
sort: { order: DESC, fields: [frontmatter___date] }
) {
edges {
node {
id
frontmatter {
date(formatString: "MMMM DD, YYYY")
title
description
author
path
thumbnail
}
}
}
}
}
`
gatsby-node.js
const path = require("path");
exports.createPages = ({ actions, graphql }) => {
const { createPage } = actions;
const postTemplate = path.resolve("src/templates/blogTemplate.js");
return graphql(`
{
allMarkdownRemark(
sort: { order: DESC, fields: [frontmatter___date] }
limit: 1000
) {
edges {
node {
id
frontmatter {
path
}
}
}
}
}
`).then(res => {
if (res.errors) {
return Promise.reject(res.errors)
}
res.data.allMarkdownRemark.edges.forEach(({ node }) => {
createPage({
path: node.frontmatter.path,
component: postTemplate,
context: {}, // additional data can be passed via context
})
})
})
};
what I have tried
I tried adding the gatsby-paginate plugin in my below gatsby-node file. But I am getting a 404 error when I now click on a individual blog page link.
Gatsby-node.js
const path = require("path");
const paginate = require('gatsby-paginate')
exports.createPages = async ({ actions, graphql }) => {
const { createPage } = actions;
//const postTemplate = path.resolve("src/templates/blogTemplate.js");
const ya = await graphql(`
{
allMarkdownRemark(
sort: { order: DESC, fields: [frontmatter___date] }
limit: 1000
) {
edges {
node {
id
frontmatter {
path
}
}
}
}
}
`);
paginate({
createPage,
items: ya.data.allMarkdownRemark.node,
itemsPerPage: 2,
pathPrefix: '/blog',
component: path.resolve("src/templates/blogTemplate.js")
});
ya.data.allMarkdownRemark.node.map(articleData =>
createPage({
path: node.frontmatter.path,
component: path.resolve("src/components/post.js"),
context: {}, // additional data can be passed via context
})
);
}
Upvotes: 0
Views: 820
Reputation: 411
I resolved the issue, the error was in my gatsby-node.js file.
Breaking both templates into separate variables and then passing the data into each template was the correct approach to what I was trying to achieve
See below gatsby-node.js file
const path = require('path')
const { slugify } = require('./src/util/utilityFunctions')
const _ = require('lodash')
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
// Page templates
const templates = {
post: path.resolve('src/templates/single-post.js'),
postList: path.resolve('src/templates/post-list.js')
}
const res = await graphql(`
{
allMarkdownRemark {
edges {
node {
frontmatter {
author
tags
}
fields {
slug
}
}
}
}
}
`)
if (res.errors) return Promise.reject(res.errors)
// Extracting all posts from res
const posts = res.data.allMarkdownRemark.edges
// Create single post pages
posts.forEach(({ node }) => {
createPage({
path: node.fields.slug,
component: templates.post,
context: {
// Passing slug for template to use to fetch the post
slug: node.fields.slug
},
})
})
// Create posts pagination pages
const postsPerPage = 4
const numberOfPages = Math.ceil(posts.length / postsPerPage)
Array.from({ length: numberOfPages }).forEach((_, index) => {
const isFirstPage = index === 0
const currentPage = index + 1
// Skip first page because of index.js
if (isFirstPage) return
createPage({
path: `/page/${currentPage}`,
component: templates.postList,
context: {
limit: postsPerPage,
skip: index * postsPerPage,
numberOfPages: numberOfPages,
currentPage: currentPage,
},
})
})
}
Upvotes: 1