GatsbyWebサイトでの高度なGraphQLの使用
公開: 2022-03-102015年にGraphQLがリリースされる前は、Representational State Transfer(REST)がAPIとのインターフェースをとる主な方法でした。 したがって、GraphQLの導入は、ソフトウェア開発における大きな変化でした。
最新の静的サイトジェネレーターとして、GatsbyはGraphQLを活用して、データをフレームワークに取り込み、操作するための簡潔な方法論を提供します。 この記事では、GraphQLと、Gatsbyで高度なデータソーシングと変換を構築および実装することにより、GraphQLをGatsbyWebサイトに統合する方法について詳しく見ていきます。 その結果、出版社のブログが作成され、出版社は著者のコンテンツを共有するために使用できます。
GraphQLとは何ですか?
QLという名前のとおり、GraphQLは、ソースからデータをプルする方法に柔軟性と効率を提供するために作成された一連のツールと組み合わされたクエリ言語です。 GraphQLを使用すると、クライアント/コンシューマーは必要なデータを正確に要求できます。 サーバー/プロバイダーは、クエリで指定された要件に一致するJSON応答署名で応答します。 これにより、データのニーズを宣言的に表現できます。
なぜGraphQLを使用するのですか?
Gatsbyは静的サイトジェネレーターとして静的ファイルを保存するため、データのクエリはほぼ不可能です。 多くの場合、単一のブログ投稿ページのように動的である必要があるページコンポーネントがあるため、ブログ投稿をマークダウンファイルに保存するのと同じように、ソースからデータを取得して必要な形式に変換する必要があります。 一部のプラグインは、さまざまなソースからのデータを提供します。これにより、ソースから必要なデータをクエリして変換することができます。
gatsby.orgのリストによると、GraphQLはGatsbyで次のことに役立ちます。
- ボイラープレートを排除する
- フロントエンドの複雑さをクエリにプッシュする
- 現代のアプリケーションの常に複雑なデータに最適なソリューションを提供する
- 最後に、コードの膨張を取り除き、それによってパフォーマンスを向上させます。
GraphQLの概念
Gatsbyは、広く使用されているものと同じGraphQLの考え方を維持しています。 これらの概念のいくつかは次のとおりです。
スキーマ定義言語
GraphQL SDLは、GraphQLに組み込まれている型システムであり、これを使用してデータの新しい型を作成できます。
国のタイプを宣言できます。その属性には、名前、大陸、人口、GDP、および州の数を含めることができます。
以下の例として、 Aleemという名前の新しいタイプを作成しました。 文字列の配列である必要のないhobbies
がありますが、国、婚姻状況、投稿が必要です! それらには、別のタイプのPostを参照するpostsも含まれます。
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: [{...}, {...}, {...}] } ]
ネストされたフィールドもクエリできます。投稿タイプの投稿のように、タイトルだけを要求できます。
query { authors(country: 'Nigeria') { country, posts { title } } }
また、国を返すナイジェリアに一致するAuthorタイプを返し、タイトルフィールドのみのオブジェクトを含む配列を投稿する必要があります。
GraphQLを使用したGatsby
GraphQLが変換できるデータを提供するサーバー/サービスのオーバーヘッドを回避するために、Gatsbyはビルド時にGraphQLクエリを実行します。 データはビルドプロセス中にコンポーネントに提供されるため、サーバーがなくてもブラウザー内ですぐに利用できます。
それでも、Gatsbyは、ブラウザーでGraphiQLなどの他のGraphQLクライアントから照会できるサーバーとして実行できます。
GraphQLと相互作用するギャツビーの方法
GatsbyがGraphQLと対話できる場所は、gatsby-node.jsAPIファイルとページコンポーネントの2つです。
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のデータレイヤーからマークダウンファイルをフェッチしました。 そして、これを挿入してページを作成し、Gatsbyデータレイヤー内の既存のデータを変更できます。
ページコンポーネント
/ pagesディレクトリ内のページコンポーネントまたはcreatePage
アクションによってレンダリングされたテンプレートは、 gatsby
モジュールからgraphql
をインポートし、 pageQuery
をエクスポートできます。 次に、Gatsbyは、解決されたデータを含むページコンポーネントの小道具に新しい小道具data
を挿入します。
import React from "react"; import { graphql } from "gatsby"; const Page = props => { return
{JSON.stringify(props.data)}; }; export const pageQuery = graphql` クエリ{...} `; デフォルトのページをエクスポートします。
その他のコンポーネント
他のコンポーネントは、 gatsby
モジュールからgraphql
およびStaticQuery
コンポーネントをインポートし、 <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のエコシステムのプラグインを使用していくつかの機能を導入し、GraphQLクエリのロジックを使用して、複数の著者の出版物に対応できる発行者のブログを作成します。
作成するブログの最終バージョンはここにあります。また、コードはGithubでホストされています。
プロジェクトの初期化
他のGatsbyWebサイトと同様に、スターターから初期化します。ここでは、高度なスターターを使用しますが、ユースケースに対応するように変更します。
最初にこのGithubリポジトリのクローンを作成し、作業ブランチをdev-initに変更してから、プロジェクトのフォルダーからnpm run develop
developmentを実行して、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
は、作成された月ごとに投稿をグループ化します。
ブログ投稿のコンテンツには、 title
、 date
、作成author
、 category
、 tags
がフロントマターとして含まれています。これを使用して、投稿を区別し、さらに処理を行います。残りのコンテンツは投稿の本文です。
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.
投稿コンテンツの表示
Markdownの投稿をHTMLでレンダリングする前に、いくつかの処理を行う必要があります。 まず、ファイルを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で終わるすべてのファイルを、マークダウンをHTMLとしてレンダリングするためのすべてのコメントフィールドを持つノードに変換するためのコメントトランスフォーマープラグインが含まれています。
最後に、 gatsby-transformer-remark
によって生成されたノードでの操作にプラグインを含めました。
gatsby-config.js
ファイルの実装
プロジェクトルートのgatsby-node.js内で、 createPage
という名前の関数をエクスポートし、関数のコンテンツを取得して、graphQLヘルパーを使用してGatsbyJSのコンテンツレイヤーからノードをプルすることができます。
このページの最初の更新には、MarkDownリマークノードにスラッグが設定されていることを確認することが含まれます。 onCreateNode APIをリッスンし、ノードを作成して、それがMarkdownRemarkのタイプであるかどうかを判断してから、ノードを更新してそれに応じてスラッグと日付を含めます。
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を実装して、すべてのマークダウンをクエリし、上記で作成したスラッグとしてパスを使用してページを作成できます。 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
ヘルパーを使用して、コンテンツレイヤーからデータをクエリします。 これを行うために標準のGraphqlクエリを使用し、 allMarkdownRemark
タイプからコンテンツを取得するためのクエリを渡しました。 次に、作成された日付で投稿を並べ替えるために先に進みました。
次に、インポートされた構成オブジェクトからpostPerPage
プロパティを取得しました。これは、投稿の総数を1ページの指定された投稿数にチャンクダウンするために使用されます。
ページネーションをサポートするリストページを作成するには、制限、pageNumber、およびリストをレンダリングするコンポーネントにスキップするページ数を渡す必要があります。 これは、 createPage
オブジェクトのコンテキストプロパティを使用して実現しています。 ページからこれらのプロパティにアクセスして、制限内の投稿をフェッチするための別のgraphqlクエリを作成します。
また、リストに同じテンプレートコンポーネントを使用しており、先に定義したチャンク配列のインデックスを利用してパスのみが変更されていることにも気付くでしょう。 Gatsbyは、 /{chunkIndex}
に一致する特定のURLに必要なデータを渡すため、最初の10件の投稿に/
を、次の10件の投稿に/2
を設定できます。
投稿リストのレンダリング
これらのページをレンダリングするコンポーネントは、プロジェクトフォルダーのsrc/templates/singlePost/index.js
にあります。 また、createPagesプロセスから受け取った制限とページクエリパラメーターをプルして、現在のページの範囲内の投稿についてgatsbyにクエリを実行するgraphql
ヘルパーをエクスポートします。
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
ファイル内にプログラムでページを作成する必要があります。 まず、コンテンツをレンダリングするための新しいコンポーネントを定義する必要があります。このために、 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ヘルパーを使用して、createPagesAPIを介してページに送信されるスラッグクエリによってページを引き出しています。
次に、 createPages
関数の最後にgatsby-node.jsに以下のコードを追加する必要があります。
// 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}」にアクセスして、そのページのマークダウンファイルのコンテンツをHTMLとしてレンダリングすることもできます。 例として、https:// localhost:8000 / the-butterfly-of-the-edgeは、すべての有効なスラッグと同様に、マークダウン用に変換されたHTMLをcontent/2020_05/01.md
にロードする必要があります。 すごい!
カテゴリとタグのレンダリング
単一の投稿テンプレートコンポーネントには、 /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 } } } } } `;
注目すべきは、タグとカテゴリの両方のコンポーネント内で、投稿のコンテンツをさらに読むために単一の投稿ページへのリンクをレンダリングすることです。
著者のサポートの追加
複数の作成者をサポートするには、投稿コンテンツにいくつかの変更を加え、新しい概念を導入する必要があります。
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
関数に以下のコードを追加する必要があります
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を呼び出して、作成者とauthorDetails
者の詳細を区別するためにmdField
を渡すページを作成します。
著者の投稿のレンダリング
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のWebサイトでデータをクエリするために広く使用されているパターンを理解しました。
GraphQLは非常に強力であり、サーバー上でのデータ変更などの他のことも実行できます。 Gatsbyは実行時にデータを更新する必要がないため、GraphQLのミューテーション機能をサポートしていません。
GraphQLは優れたテクノロジーであり、Gatsbyはフレームワークでの使用を非常に面白くしています。
参考文献
- GraphQLのGatsbyサポート
- GatsbyがGraphQLを使用する理由
- GatsbyのGraphQLの概念
- GraphQLの方法:基本概念
- GraphQLのスキーマ定義言語
- GraphQLの紹介
- ギャツビーアドバンスドスターター