Gatsby 網站中的高級 GraphQL 使用

已發表: 2022-03-10
快速總結 ↬在本文中,Aleem Isiaka 解釋了什麼是 GraphQL 查詢結構,以及如何使用它們與 Gatsby 網站的數據訪問層進行交互。 讓我們通過使用來自不同來源的匹配數據來看看 GraphQL 在 Gatsby 網站中的一些高級用例。

在 2015 年 GraphQL 發布之前,表示狀態傳輸 (REST) 是與 API 交互的主要方式。 因此,GraphQL 的引入是軟件開發的一個重大變化。

作為現代靜態站點生成器,Gatsby 利用 GraphQL 提供了一種簡潔的方法來將數據引入和操作到框架中。 在本文中,我們將仔細研究 GraphQL 以及如何通過在 Gatsby 中構建和實施高級數據源和轉換將其集成到 Gatsby 網站中。 結果是任何出版公司都可以使用出版商​​的博客來分享其作者的內容。

什麼是 GraphQL?

顧名思義, GraphQL是一種查詢語言,它結合了一組工具,旨在為我們從源中提取數據的方式提供靈活性和效率。 使用 GraphQL,客戶端/消費者可以準確地請求它需要的數據。 服務器/提供者使用與查詢中指定的要求匹配的 JSON 響應簽名進行響應。 它允許我們以聲明的方式表達我們的數據需求。

為什麼使用 GraphQL?

作為靜態站點生成器,Gatsby 存儲靜態文件,這使得查詢數據幾乎是不可能的。 通常有頁面組件必須像單個博客文章頁面一樣是動態的,因此需要從源中提取數據並將其轉換為所需的格式,就像將博客文章存儲在降價文件中一樣。 一些插件提供來自各種來源的數據,這使您可以從某個來源查詢和轉換所需的數據。

根據 gatsby.org 上的列表,GraphQL 在 Gatsby 中很有用:

  • 消除樣板
  • 將前端複雜性推送到查詢中
  • 為現代應用程序中始終複雜的數據提供完美的解決方案
  • 最後,消除代碼膨脹,從而提高性能。

GraphQL 概念

Gatsby 保持與廣泛使用的 GraphQL 相同的思想; 其中一些概念是:

模式定義語言

GraphQL SDL 是一個集成到 GraphQL 中的類型系統,您可以使用它為您的數據創建新類型。

我們可以為一個國家聲明一個類型,它的屬性可以包括名稱、大陸、人口、gdp 和州數。

作為下面的示例,我們創建了一個名為Aleem的新類型。 它的hobbies是一系列字符串,不是必需的,但由於! 它們包括,還帖子引用另一種類型, Post

 type Author { name: String!, hobbies: [String] country: String! married: Boolean! posts: [Post!] } type Post { title: String! body: String! } type Query { author: Author } schema { query: Query }

查詢

我們可以使用查詢從 GraphQL 源中提取數據。

考慮如下數據集

{ data: { author: [ { hobbies: ["travelling", "reading"], married: false, country: "Nigeria", name: "Aleem Isiaka", posts: [ { title: "Learn more about how to improve your Gatsby website", }, { title: "The ultimate guide to GatsbyJS", }, { title: "How to start a blog with only GatsbyJS", }, ], }, ], }, };

我們可以有一個查詢來從數據中獲取國家和帖子:

 query { authors { country, posts { title } } }

我們將獲得的響應應該包含博客文章的 JSON 數據,僅包含標題,僅此而已:

 [ { country: “Nigeria”, posts: [{...}, {...}, {...}] }, { country: “Tunisia”, posts: [] }, { title: “Ghana”, posts: []}, ]

我們還可以使用參數作為查詢的條件:

 query { authors (country: “Nigeria”) { country, posts { title } } }

哪個應該返回

[ { country: “Nigeria”, posts: [{...}, {...}, {...}] } ]

也可以查詢嵌套字段,比如 Post 類型的帖子,你可以只要求標題:

 query { authors(country: 'Nigeria') { country, posts { title } } }

它應該返回任何與尼日利亞匹配的作者類型,返回國家和帖子數組,其中包含僅包含標題字段的對象。

使用 GraphQL 的蓋茨比

為了避免使用服務於 GraphQL 可以轉換的數據的服務器/服務的開銷,Gatsby 在構建時執行 GraphQL 查詢。 在構建過程中向組件提供數據,使它們無需服務器即可在瀏覽器中輕鬆使用。

儘管如此,Gatsby 仍然可以作為服務器運行,該服務器可以被其他 GraphQL 客戶端(如 GraphiQL)在瀏覽器中查詢。

Gatsby 與 GraphQL 的交互方式

Gatsby 可以在兩個地方與 GraphQL 交互,通過 gatsby-node.js API 文件和通過頁面組件。

gatsby-node.js

createPage API 可以配置為一個函數,它將接收一個graphql助手作為傳遞給函數的第一個參數中的項目的一部分。

 // gatsby-node.js source: https://www.gatsbyjs.org/docs/node-apis/#createPages exports.createPages = async ({ graphql, actions }) => { const result = await graphql(` query loadPagesQuery ($limit: Int!) { allMarkdownRemark(limit: $limit) { edges { node { frontmatter { slug } } } } }`) }

在上面的代碼中,我們使用了 GraphQL 助手從 Gatsby 的數據層獲取 markdown 文件。 我們可以注入它來創建一個頁面並修改 Gatsby 數據層中的現有數據。

頁面組件

/pages 目錄中的頁面組件或由createPage API 操作呈現的模板可以從gatsby模塊導入graphql並導出pageQuery 。 反過來,Gatsby 會將新的 prop data注入到包含已解析數據的頁面組件的 props 中。

 import React from "react"; import { graphql } from "gatsby"; const Page = props => { return
{JSON.stringify(props.data)}
; }; 導出 const pageQuery = graphql` 詢問 { ... } `; 導出默認頁面;

在其他組件中

其他組件可以從gatsby模塊導入graphqlStaticQuery組件,渲染<StaticQuery/>傳遞實現 Graphql 幫助器的查詢道具並渲染以獲取返回的數據。

 import React from "react"; import { StaticQuery, graphql } from "gatsby"; const Brand = props => { return ( <div> <h1>{data.site.siteMetadata.title}</h1> </div> ); }; const Navbar = props => { return ( <StaticQuery query={graphql` query { site { siteMetadata { title } } } `} render={data => <Brand data={data} {...props} />} /> ); }; export default Navbar;

建立一個現代和先進的 Gatsby 出版博客

在本節中,我們將介紹創建支持按作者標記、分類、分頁和分組文章的博客的過程。 我們將使用 Gatsby 生態系統的插件來引入一些功能,並使用 GraphQL 查詢中的邏輯來製作發布者的博客,以便為多個作者發布做好準備。

我們將構建的博客的最終版本可以在這裡找到,代碼也託管在 Github 上。

初始化項目

像任何 Gatsby 網站一樣,我們從啟動器進行初始化,在這裡我們將使用高級啟動器,但經過修改以適應我們的用例。

首先克隆這個 Github 存儲庫,將工作分支更改為 dev-init,然後從項目文件夾運行npm run develop以啟動開發服務器,使站點在 https://localhost:8000 可用。

 git clone [email protected]:limistah/modern-gatsby-starter.git cd modern-gatsby-starter git checkout dev-init npm install npm run develop

訪問 https://localhost:8000 將顯示該分支的默認主頁。

創建博客文章內容

項目存儲庫中包含的一些帖子內容可以在 dev-blog-content 分支中訪問。 內容目錄的組織類似於/content/YYYY_MM/DD.md ,它按一年中創建的月份對帖子進行分組。

博文內容有titledateauthorcategorytags作為frontmatter,我們將用它們來區分一篇博文並做一些進一步的處理,而其餘的內容是博文的正文。

 title: "Bold Mage" date: "2020-07-12" author: "Tunde Isiaka" category: "tech" tags: - programming - stuff - Ice cream - other --- # Donut I love macaroon chocolate bar Oat cake marshmallow lollipop fruitcake I love jelly-o. Gummi bears cake wafer chocolate bar pie. Marshmallow pastry powder chocolate cake candy chupa chups. Jelly beans powder souffle biscuit pie macaroon chocolate cake. Marzipan lemon drops chupa chups sweet cookie sesame snaps jelly halvah.

顯示帖子內容

在我們可以用 HTML 渲染我們的 Markdown 帖子之前,我們必須做一些處理。 首先,將文件加載到 Gatsby 存儲中,將 MD 解析為 HTML,鏈接圖像依賴項和點贊。 為了緩解這種情況,我們將使用 Gatsby 生態系統的大量插件。

我們可以通過更新項目根目錄下的 gatsby-config.js 來使用這些插件,如下所示:

 module.exports = { siteMetadata: {}, plugins: [ { resolve: "gatsby-source-filesystem", options: { name: "assets", path: `${__dirname}/static/`, }, }, { resolve: "gatsby-source-filesystem", options: { name: "posts", path: `${__dirname}/content/`, }, }, { resolve: "gatsby-transformer-remark", options: { plugins: [ { resolve: `gatsby-remark-relative-images`, }, { resolve: "gatsby-remark-images", options: { maxWidth: 690, }, }, { resolve: "gatsby-remark-responsive-iframe", }, "gatsby-remark-copy-linked-files", "gatsby-remark-autolink-headers", "gatsby-remark-prismjs", ], }, }, ], };

我們已指示 gatsby 包含插件以幫助我們執行一些操作,特別是從 /static 文件夾中提取靜態文件和 /content 中的文件用於我們的博客文章。 此外,我們還包含了一個備註轉換器插件,用於將所有以 .md 或 .markdown 結尾的文件轉換為具有所有備註字段的節點,以將 Markdown 呈現為 HTML。

最後,我們在gatsby-transformer-remark生成的節點上包含了插件。

實現gatsby-config.js API 文件

展望未來,在項目根目錄的 gatsby-node.js 中,我們可以導出一個名為createPage的函數,並擁有該函數的內容,以使用 graphQL 助手從 GatsbyJS 的內容層中提取節點。

此頁面的第一個更新將包括確保我們在 MarkDown 備註節點上設置了一個 slug。 我們將監聽 onCreateNode API 並獲取創建的節點以確定它是否是 MarkdownRemark 類型,然後我們更新節點以包含相應的 slug 和日期。

 const path = require("path"); const _ = require("lodash"); const moment = require("moment"); const config = require("./config"); // Called each time a new node is created exports.onCreateNode = ({ node, actions, getNode }) => { // A Gatsby API action to add a new field to a node const { createNodeField } = actions; // The field that would be included let slug; // The currently created node is a MarkdownRemark type if (node.internal.type === "MarkdownRemark") { // Recall, we are using gatsby-source-filesystem? // This pulls the parent(File) node, // instead of the current MarkdownRemark node const fileNode = getNode(node.parent); const parsedFilePath = path.parse(fileNode.relativePath); if ( Object.prototype.hasOwnProperty.call(node, "frontmatter") && Object.prototype.hasOwnProperty.call(node.frontmatter, "title") ) { // The node is a valid remark type and has a title, // Use the title as the slug for the node. slug = `/${_.kebabCase(node.frontmatter.title)}`; } else if (parsedFilePath.name !== "index" && parsedFilePath.dir !== "") { // File is in a directory and the name is not index // eg content/2020_02/learner/post.md slug = `/${parsedFilePath.dir}/${parsedFilePath.name}/`; } else if (parsedFilePath.dir === "") { // File is not in a subdirectory slug = `/${parsedFilePath.name}/`; } else { // File is in a subdirectory, and name of the file is index // eg content/2020_02/learner/index.md slug = `/${parsedFilePath.dir}/`; } if (Object.prototype.hasOwnProperty.call(node, "frontmatter")) { if (Object.prototype.hasOwnProperty.call(node.frontmatter, "slug")) slug = `/${_.kebabCase(node.frontmatter.slug)}`; if (Object.prototype.hasOwnProperty.call(node.frontmatter, "date")) { const date = moment(new Date(node.frontmatter.date), "DD/MM/YYYY"); if (!date.isValid) console.warn(`WARNING: Invalid date.`, node.frontmatter); // MarkdownRemark does not include date by default createNodeField({ node, name: "date", value: date.toISOString() }); } } createNodeField({ node, name: "slug", value: slug }); } };

帖子列表

此時,我們可以實現createPages API 來查詢所有降價,並創建一個頁面,其路徑為我們在上面創建的 slug。 在 Github 上查看。

 //gatsby-node.js // previous code // Create Pages Programatically! exports.createPages = async ({ graphql, actions }) => { // Pulls the createPage action from the Actions API const { createPage } = actions; // Template to use to render the post converted HTML const postPage = path.resolve("./src/templates/singlePost/index.js"); // Get all the markdown parsed through the help of gatsby-source-filesystem and gatsby-transformer-remark const allMarkdownResult = await graphql(` { allMarkdownRemark { edges { node { fields { slug } frontmatter { title tags category date author } } } } } `); // Throws if any error occur while fetching the markdown files if (allMarkdownResult.errors) { console.error(allMarkdownResult.errors); throw allMarkdownResult.errors; } // Items/Details are stored inside of edges const postsEdges = allMarkdownResult.data.allMarkdownRemark.edges; // Sort posts postsEdges.sort((postA, postB) => { const dateA = moment( postA.node.frontmatter.date, siteConfig.dateFromFormat ); const dateB = moment( postB.node.frontmatter.date, siteConfig.dateFromFormat ); if (dateA.isBefore(dateB)) return 1; if (dateB.isBefore(dateA)) return -1; return 0; }); // Pagination Support for posts const paginatedListingTemplate = path.resolve( "./src/templates/paginatedListing/index.js" ); const { postsPerPage } = config; if (postsPerPage) { // Get the number of pages that can be accommodated const pageCount = Math.ceil(postsEdges.length / postsPerPage); // Creates an empty array Array.from({ length: pageCount }).forEach((__value__, index) => { const pageNumber = index + 1; createPage({ path: index === 0 ? `/posts` : `/posts/${pageNumber}/`, component: paginatedListingTemplate, context: { limit: postsPerPage, skip: index * postsPerPage, pageCount, currentPageNumber: pageNumber, }, }); }); } else { // Load the landing page instead createPage({ path: `/`, component: landingPage, }); } };

createPages函數中,我們使用 Gatsby 提供的graphql helper 從內容層查詢數據。 我們使用標準的 Graphql 查詢來執行此操作,並通過查詢從allMarkdownRemark類型中獲取內容。 然後繼續按創建日期對帖子進行排序。

然後,我們從導入的配置對像中提取了一個postPerPage屬性,該屬性用於將帖子總數分塊為單個頁面的指定帖子數。

要創建支持分頁的列表頁面,我們需要傳入限制、pageNumber 和要跳轉到將呈現列表的組件的頁數。 我們使用createPage配置對象的 context 屬性來實現這一點。 我們將從頁面訪問這些屬性以進行另一個 graphql 查詢以獲取限制內的帖子。

我們還可以注意到,我們在列表中使用了相同的模板組件,並且只有路徑在使用我們之前定義的塊數組的索引進行更改。 Gatsby 將傳遞與/{chunkIndex}匹配的給定 URL 的必要數據,因此我們可以將/用於前十個帖子,將/2用於接下來的十個帖子。

現代博客主頁
現代博客主頁(大預覽)

渲染帖子列表

渲染這些頁面的組件可以在項目文件夾的src/templates/singlePost/index.js中找到。 它還導出了一個graphql幫助程序,該幫助程序提取從 createPages 進程接收到的限制和頁面查詢參數,以查詢 gatsby 以獲取當前頁面範圍內的帖子。

 import React from "react"; import { graphql, Link } from "gatsby"; import Layout from "../../layout"; import PostListing from "../../components/PostListing"; import "./index.css"; const Pagination = ({ currentPageNum, pageCount }) => { const prevPage = currentPageNum - 1 === 1 ? "/" : `/${currentPageNum - 1}/`; const nextPage = `/${currentPageNum + 1}/`; const isFirstPage = currentPageNum === 1; const isLastPage = currentPageNum === pageCount; return ( <div className="paging-container"> {!isFirstPage && <Link to={prevPage}>Previous</Link>} {[...Array(pageCount)].map((_val, index) => { const pageNum = index + 1; return ( <Link key={`listing-page-${pageNum}`} to={pageNum === 1 ? "/" : `/${pageNum}/`} > {pageNum} </Link> ); })} {!isLastPage && <Link to={nextPage}>Next</Link>} </div> ); }; export default (props) => { const { data, pageContext } = props; const postEdges = data.allMarkdownRemark.edges; const { currentPageNum, pageCount } = pageContext; return ( <Layout> <div className="listing-container"> <div className="posts-container"> <PostListing postEdges={postEdges} /> </div> <Pagination pageCount={pageCount} currentPageNum={currentPageNum} /> </div> </Layout> ); }; /* eslint no-undef: "off" */ export const pageQuery = graphql` query ListingQuery($skip: Int!, $limit: Int!) { allMarkdownRemark( sort: { fields: [fields___date], order: DESC } limit: $limit skip: $skip ) { edges { node { fields { slug date } excerpt timeToRead frontmatter { title tags author category date } } } } } `;

帖子頁面

要查看頁面的內容,我們需要在gatsby-node.js API 文件中以編程方式創建頁面。 首先,我們必須定義一個新組件來渲染內容,為此,我們有src/templates/singlePost/index.jsx

 import React from "react"; import { graphql, Link } from "gatsby"; import _ from "lodash"; import Layout from "../../layout"; import "./b16-tomorrow-dark.css"; import "./index.css"; import PostTags from "../../components/PostTags"; export default class PostTemplate extends React.Component { render() { const { data, pageContext } = this.props; const { slug } = pageContext; const postNode = data.markdownRemark; const post = postNode.frontmatter; if (!post.id) { post.id = slug; } return ( <Layout> <div> <div> <h1>{post.title}</h1> <div className="category"> Posted to{" "} <em> <Link key={post.category} style={{ textDecoration: "none" }} to={`/category/${_.kebabCase(post.category)}`} > <a>{post.category}</a> </Link> </em> </div> <PostTags tags={post.tags} /> <div dangerouslySetInnerHTML={{ __html: postNode.html }} /> </div> </div> </Layout> ); } } /* eslint no-undef: "off" */ export const pageQuery = graphql` query BlogPostBySlug($slug: String!) { markdownRemark(fields: { slug: { eq: $slug } }) { html timeToRead excerpt frontmatter { title date category tags } fields { slug date } } } `;

同樣,我們使用 graphQL 助手通過 slug 查詢提取頁面,該查詢將通過 createPages API 發送到頁面。

接下來,我們應該將以下代碼添加到 gatsby-node.js 的createPages API 函數末尾。

 // Template to use to render the post converted HTML const postPage = path.resolve("./src/templates/singlePost/index.jsx"); // Loops through all the post nodes postsEdges.forEach((edge, index) => { // Create post pages createPage({ path: edge.node.fields.slug, component: postPage, context: { slug: edge.node.fields.slug, }, }); });

我們可以訪問 '/{pageSlug}' 並讓它將該頁面的 markdown 文件的內容呈現為 HTML。 例如,https://localhost:8000/the-butterfly-of-the-edge 應該在content/2020_05/01.md加載轉換後的 HTML,類似於所有有效的 slug。 偉大的!

現代博客文章頁面
現代博客文章頁面(大預覽)

渲染類別和標籤

單個帖子模板組件具有指向/categories/{categoryName}格式的頁面的鏈接,以列出具有相似類別的帖子。

當我們在gatsby-node.js文件中構建單個帖子頁面時,我們可以首先捕獲所有類別和標籤,然後為每個捕獲的類別/標籤創建頁面,並傳遞類別/標籤名稱。

在 gatsby-node.js 中對創建單個帖子頁面的部分進行了修改,如下所示:

 const categorySet = new Set(); const tagSet = new Set(); const categoriesListing = path.resolve( "./src/templates/categoriesListing/index.jsx" ); // Template to use to render posts based on categories const tagsListingPage = path.resolve("./src/templates/tagsListing/index.jsx"); // Loops through all the post nodes postsEdges.forEach((edge, index) => { // Generate a list of categories if (edge.node.frontmatter.category) { categorySet.add(edge.node.frontmatter.category); } // Generate a list of tags if (edge.node.frontmatter.tags) { edge.node.frontmatter.tags.forEach((tag) => { tagSet.add(tag); }); } // Create post pages createPage({ path: edge.node.fields.slug, component: postPage, context: { slug: edge.node.fields.slug, }, }); });

在按標籤列出帖子的組件中,我們可以讓pageQuery導出查詢 graphql 的帖子,包括該標籤在其標籤列表中。 我們將使用 graphql 的filter功能和 $in 運算符來實現:

 // src/templates/tagsListing/ import React from "react"; import { graphql } from "gatsby"; import Layout from "../../layout"; import PostListing from "../../components/PostListing"; export default ({ pageContext, data }) => { const { tag } = pageContext; const postEdges = data.allMarkdownRemark.edges; return ( <Layout> <div className="tag-container"> <div>Posts posted with {tag}</div> <PostListing postEdges={postEdges} /> </div> </Layout> ); }; /* eslint no-undef: "off" */ export const pageQuery = graphql` query TagPage($tag: String) { allMarkdownRemark( limit: 1000 sort: { fields: [fields___date], order: DESC } filter: { frontmatter: { tags: { in: [$tag] } } } ) { totalCount edges { node { fields { slug date } excerpt timeToRead frontmatter { title tags author date } } } } } `;

我們在分類列表組件中也有相同的過程,不同的是我們只需要找到與我們傳遞給它的分類精確匹配的位置。

 // src/templates/categoriesListing/index.jsx import React from "react"; import { graphql } from "gatsby"; import Layout from "../../layout"; import PostListing from "../../components/PostListing"; export default ({ pageContext, data }) => { const { category } = pageContext; const postEdges = data.allMarkdownRemark.edges; return ( <Layout> <div className="category-container"> <div>Posts posted to {category}</div> <PostListing postEdges={postEdges} /> </div> </Layout> ); }; /* eslint no-undef: "off" */ export const pageQuery = graphql` query CategoryPage($category: String) { allMarkdownRemark( limit: 1000 sort: { fields: [fields___date], order: DESC } filter: { frontmatter: { category: { eq: $category } } } ) { totalCount edges { node { fields { slug date } excerpt timeToRead frontmatter { title tags author date } } } } } `;

值得注意的是,在標籤和類別組件中,我們呈現指向單個帖子頁面的鏈接,以便進一步閱讀帖子的內容。

帶有標籤的 Hello World 單個帖子頁面
帶有類別標籤的現代帖子(大預覽)

添加對作者的支持

為了支持多個作者,我們必須對我們的帖子內容進行一些修改並引入新概念。

加載 JSON 文件

首先,我們應該能夠將作者的內容存儲在 JSON 文件中,如下所示:

 { "mdField": "aleem", "name": "Aleem Isiaka", "email": "[email protected]", "location": "Lagos, Nigeria", "avatar": "https://api.adorable.io/avatars/55/[email protected]", "description": "Yeah, I like animals better than people sometimes... Especially dogs. Dogs are the best. Every time you come home, they act like they haven't seen you in a year. And the good thing about dogs... is they got different dogs for different people.", "userLinks": [ { "label": "GitHub", "url": "https://github.com/limistah/modern-gatsby-starter", "iconClassName": "fa fa-github" }, { "label": "Twitter", "url": "https://twitter.com/limistah", "iconClassName": "fa fa-twitter" }, { "label": "Email", "url": "mailto:[email protected]", "iconClassName": "fa fa-envelope" } ] }

我們會將它們作為/authors存儲在項目根目錄中的作者目錄中。 請注意,作者 JSON 具有mdField ,它將是我們將介紹給降價博客內容的作者字段的唯一標識符; 這確保了作者可以擁有多個個人資料。

接下來,我們必須更新gatsby-config.js插件,指示gatsby-source-filesystem將內容從authors/目錄加載到文件節點中。

 // gatsby-config.js { resolve: `gatsby-source-filesystem`, options: { name: "authors", path: `${__dirname}/authors/`, }, }

最後,我們將安裝gatsby-transform-json來轉換創建的 JSON 文件,以便於處理和正確處理。

 npm install gatsby-transformer-json --save

並將其包含在gatsby-config.js的插件中,

 module.exports = { plugins: [ // ...other plugins `gatsby-transformer-json` ], };

查詢和創建作者頁面

首先,我們需要在gatsby-config.js中的authors/目錄中查詢所有已加載到數據層的作者,我們應該將以下代碼附加到createPages API 函數

const authorsListingPage = path.resolve( "./src/templates/authorsListing/index.jsx" ); const allAuthorsJson = await graphql(` { allAuthorsJson { edges { node { id avatar mdField location name email description userLinks { iconClassName label url } } } } } `); const authorsEdges = allAuthorsJson.data.allAuthorsJson.edges; authorsEdges.forEach((author) => { createPage({ path: `/authors/${_.kebabCase(author.node.mdField)}/`, component: authorsListingPage, context: { authorMdField: author.node.mdField, authorDetails: author.node, }, }); });

在這個片段中,我們從 allAuthorsJson 類型中提取所有作者,然後在節點上調用 forEach 以創建一個頁面,我們在其中傳遞mdField來區分作者和authorDetails以獲取有關作者的完整信息。

渲染作者的帖子

在渲染頁面的組件中,可以在src/templates/authorsListing/index.jsx找到,我們有以下文件內容

import React from "react"; import { graphql } from "gatsby"; import Layout from "../../layout"; import PostListing from "../../components/PostListing"; import AuthorInfo from "../../components/AuthorInfo"; export default ({ pageContext, data }) => { const { authorDetails } = pageContext; const postEdges = data.allMarkdownRemark.edges; return ( <Layout> <div> <h1 style={{ textAlign: "center" }}>Author Roll</h1> <div className="category-container"> <AuthorInfo author={authorDetails} /> <PostListing postEdges={postEdges} /> </div> </div> </Layout> ); }; /* eslint no-undef: "off" */ export const pageQuery = graphql` query AuthorPage($authorMdField: String) { allMarkdownRemark( limit: 1000 sort: { fields: [fields___date], order: DESC } filter: { frontmatter: { author: { eq: $authorMdField } } } ) { totalCount edges { node { fields { slug date } excerpt timeToRead frontmatter { title tags author date } } } } } `;

在上面的代碼中,我們像我們一樣導出了pageQuery ,以創建一個 GraphQL 查詢來獲取作者匹配的帖子,我們使用$eq運算符來實現這一點,即生成指向單個帖子頁面的鏈接以供進一步閱讀。

現代博客作者頁面
現代博客作者頁面(大預覽)

結論

在 Gatsby 中,我們可以使用 GraphQL 查詢來查詢存在於其數據訪問層內部的任何數據,並使用 Gatsby 架構定義的一些構造傳遞變量。 我們已經了解瞭如何在各個地方使用graphql助手,並了解了在 GraphQL 的幫助下在 Gatsby 網站中查詢數據的廣泛使用模式。

GraphQL 非常強大,可以在服務器上做其他事情,比如數據突變。 Gatsby 不需要在運行時更新其數據,因此不支持 GraphQL 的變異特性。

GraphQL 是一項偉大的技術,Gatsby 讓它在他們的框架中使用非常有趣。

參考

  • Gatsby 對 GraphQL 的支持
  • 為什麼 Gatsby 使用 GraphQL
  • Gatsby 中的 GraphQL 概念
  • 如何 GraphQL:基本概念
  • GraphQL 中的模式定義語言
  • GraphQL 簡介
  • 蓋茨比高級入門