Как мы знаем, посты не стоит загружать на одну и ту же страницу, лучше разбить их на отдельные страницы (хотя производительность Gatsby потянет их и на одной). В этом учебном материале мы рассмотрим плагин gatsby-awesome-pagination и с его помощью попробуем разбить наш архив записей на более удобные разделы.
Создание простого блога
Начнем работу с создания простого тестового блога. Используем для этого стартер gatsby-starter-blog, поскольку он поддерживает markdown.
$ gatsby new pagination-example https://github.com/gatsbyjs/gatsby-starter-blog
$ yarn add gatsby-awesome-pagination
Разбивка на страницы
Давайте импортируем метод paginate в файл gatsby-node.js и под запросом сообщений передадим ему объект. Ему нужно всего несколько вещей, а именно действие createPage, сам массив сообщений, доступное количество элементов на странице, заголовок для новой страницы архива и ее шаблон. Когда мы сделаем этот запрос, мы получим в свойстве pageContext кучу дополнительных вещей. Это свойство мы будем использовать для управления отображаемой страницей.
const { paginate } = require('gatsby-awesome-pagination'); exports.createPages = async ({ graphql, actions }) => { const { createPage } = actions const blogPost = path.resolve(`./src/templates/blog-post.js`) const result = await graphql(` ... `) paginate({ createPage, items: result.data.allMarkdownRemark.edges, itemsPerPage: 3, pathPrefix: '/posts', component: path.resolve('src/templates/blog-archive.js') }); };
Шаблон страницы
Насколько нам известно, плагин gatsby-awesome-pagination предназначен только для постраничной верстки отдельных «архивных» страниц. Поэтому потому мы не будем добавлять нумерацию страниц на главную страницу стартера, а вместо этого сошлемся на отдельную страницу публикаций. Оформить группы публикаций на обычных страницах, вероятно, лучше всего с помощью статического запроса и чего-то вроде карусели для управления. Откройте файл index.js:
import React from "react"; import { Link, graphql } from "gatsby"; import Bio from "../components/bio"; import Layout from "../components/layout"; class BlogIndex extends React.Component { render() { const { data } = this.props; return ( <Layout location={this.props.location}> <Bio /> <Link to='/posts'><button>See All Posts</button></Link> </Layout> ) } }; export default BlogIndex;
Итак, в свойствах шаблона нашего архива, которые мы передадим в отдельный компонент Pager, уже есть доступ к pageContext запроса. Обратите внимание: вместо статического запроса нужно использовать обычный запрос, поскольку наш pageContext будет передавать значения в аргументы skip и limit, которые нам также нужно будет установить. Откройте blog-archive.js:
import Pager from '../components/pager'; export const pageQuery = graphql` query($skip: Int!, $limit: Int!) { site { ... } allMarkdownRemark( sort: { fields: [frontmatter___date], order: DESC}, skip: $skip, limit: $limit ) { edges { ... } } } `; const BlogArchive = ({ data, pageContext, location }) => { const posts = data.allMarkdownRemark.edges; return ( <Layout location={location}> {posts.map(({ node }) => { const title = node.frontmatter.title || node.fields.slug return ( <article key={node.fields.slug}> <header> <h3> <Link to={node.fields.slug}> {title} </Link> </h3> <small>{node.frontmatter.date}</small> </header> <section> <p dangerouslySetInnerHTML={{ __html: node.frontmatter.description || node.excerpt }} /> </section> </article> ) })} <Pager pageContext={pageContext} /> </Layout> ) }; export default BlogArchive;
Компонент pager
Этот компонент хранится в файле components/pager.js. Последний наш шаг – получение путей к страницам из pageContext. В pageContext вы увидите свойства skip и limit, которые передаются запросу, а также pageNumber и numberOfPages, которые позволяют сгенерировать нужное количество страниц и ссылку для каждой страницы. Откройте components/pager.js:
import React from 'react'; import { Link } from 'gatsby'; const Pager = ({ pageContext }) => { console.log(pageContext); const { previousPagePath, nextPagePath } = pageContext; return ( <nav style={{ display: 'flex', justifyContent: 'space-between' }}> <div> {previousPagePath && ( <Link to={previousPagePath}> <button>← Newer Posts</button> </Link> )} </div> <div style={{ justifySelf: 'flex-end' }}> {nextPagePath && ( <Link to={nextPagePath}> <button>Older Posts →</button> </Link> )} </div> </nav> ); }; export default Pager;
Публикации блога
Чтобы добавить навигацию между постами блога, нам даже не нужен отдельный плагин. Стартер, который мы выбрали в самом начале, уже поддерживает эту функцию, но давайте представим, что это не так, чтобы потренироваться.
В файле gatsby-node.js (где мы создаем страницы при помощи запроса) нам просто нужно добавить два поля, которые затем смогут получить доступ в pageContext. Если это первая публикация, то prev не должно существовать, иначе блог вернет последнюю запись. То же самое относится к свойству next (только оно вернет следующий пост, если таковой существует).
posts.forEach((post, index) => { createPage({ path: post.node.fields.slug, component: blogPost, context: { slug: post.node.fields.slug, prev: index === 0 ? null : posts[index - 1].node, next: index === (posts.length - 1) ? null : posts[index + 1].node }, }) });
То же самое относится к компоненту Pager: проверьте, существуют ли prev/next, вставьте их в Link, и все готово. Откройте blog-post.js:
const BlogPostTemplate = ({ data, pageContext, location }) => { const post = data.markdownRemark; const { prev, next } = pageContext; return ( <Layout location={location}> <Link to='/posts'>Archive</Link> <article> <header> <h1> {post.frontmatter.title} </h1> <p> {post.frontmatter.date} </p> </header> <section dangerouslySetInnerHTML={{ __html: post.html }} /> <hr /> </article> <nav style={{ display: 'flex', justifyContent: 'space-between' }}> <div> {prev && <Link to={prev.fields.slug} rel="prev"> ← Last Post </Link>} </div> <div style={{ justifySelf: 'flex-end' }}> {next && <Link to={next.fields.slug} rel="next"> Next Post → </Link>} </div> </nav> </Layout> ) }; export default BlogPostTemplate;
Заключение
В этом руководстве мы показали, как работает плагин gatsby-awesome-pagination. Он все еще находится в активной разработке, хотя сложно представить, как можно улучшить и его без того невероятно простой дизайн.
Читайте также: Основы Gatsby CLI: шпаргалка по командам