Erweiterte GraphQL-Nutzung auf Gatsby-Websites
Veröffentlicht: 2022-03-10Vor der Veröffentlichung von GraphQL im Jahr 2015 war Representational State Transfer (REST) die Hauptmethode für die Verbindung mit einer API. Die Einführung von GraphQL war daher eine große Veränderung in der Softwareentwicklung.
Als moderner statischer Site-Generator nutzt Gatsby GraphQL, um eine prägnante Methode zum Einbringen und Bearbeiten von Daten in das Framework bereitzustellen. In diesem Artikel werfen wir einen genaueren Blick auf GraphQL und wie wir es in eine Gatsby-Website integrieren können, indem wir erweiterte Datenbeschaffung und -transformation in Gatsby aufbauen und implementieren. Das Ergebnis ist ein Verlagsblog, das von jedem Verlag genutzt werden könnte, um Inhalte seiner Autoren zu teilen.
Was ist GraphQL?
GraphQL, das im Namen QL trägt, ist eine Abfragesprache in Kombination mit einer Reihe von Tools, die entwickelt wurden, um Flexibilität und Effizienz bei der Art und Weise zu bieten, wie wir Daten aus einer Quelle ziehen. Mit GraphQL kann ein Kunde/Verbraucher genau die Daten anfordern, die er benötigt. Der Server/Anbieter antwortet mit einer JSON-Antwortsignatur, die den in der Abfrage angegebenen Anforderungen entspricht. Es erlaubt uns, unsere Datenbedürfnisse deklarativ auszudrücken.
Warum GraphQL verwenden?
Als statischer Site-Generator speichert Gatsby statische Dateien, was das Abfragen von Daten nahezu unmöglich macht. Es gibt oft Seitenkomponenten, die dynamisch sein müssen, wie die einzelne Blogpost-Seite, sodass die Notwendigkeit entstehen würde, Daten aus einer Quelle zu ziehen und sie in das benötigte Format umzuwandeln, genau wie Blogposts in Markdown-Dateien gespeichert werden. Einige Plugins stellen Daten aus verschiedenen Quellen bereit, sodass Sie die erforderlichen Daten aus einer Quelle abfragen und transformieren müssen.
Laut einer Liste auf gatsby.org ist GraphQL in Gatsby nützlich, um:
- Boilerplate eliminieren
- Schieben Sie Frontend-Komplexitäten in Abfragen
- Bieten Sie eine perfekte Lösung für die immer komplexen Daten einer modernen Anwendung
- Schließlich, um Code Bloat zu entfernen und dadurch die Leistung zu verbessern.
GraphQL-Konzepte
Gatsby behält die gleichen Ideen von GraphQL bei, wie sie weit verbreitet sind; Einige dieser Konzepte sind:
Schemadefinitionssprache
GraphQL SDL ist ein in GraphQL integriertes Typsystem, mit dem Sie neue Typen für Ihre Daten erstellen können.
Wir können einen Typ für ein Land deklarieren, und seine Attribute könnten einen Namen, einen Kontinent, eine Bevölkerung, ein BIP und die Anzahl der Bundesstaaten enthalten.
Als Beispiel unten haben wir einen neuen Typ mit dem Namen Aleem erstellt. Es hat hobbies
, die eine Reihe von Zeichenfolgen sind und nicht erforderlich sind, aber Land, Familienstand und Posten werden aufgrund der benötigt ! Dazu gehören auch Posts, die auf einen anderen Typ verweisen, 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 }
Abfragen
Wir können Abfragen verwenden, um Daten aus einer GraphQL-Quelle abzurufen.
Betrachten Sie einen Datensatz wie den folgenden
{ 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", }, ], }, ], }, };
Wir können eine Abfrage haben, um das Land und die Beiträge aus den Daten abzurufen:
query { authors { country, posts { title } } }
Die Antwort, die wir erhalten, sollte JSON-Daten von Blog-Beiträgen mit nur dem Titel und nicht mehr enthalten:
[ { country: “Nigeria”, posts: [{...}, {...}, {...}] }, { country: “Tunisia”, posts: [] }, { title: “Ghana”, posts: []}, ]
Wir können auch Argumente als Bedingungen für eine Abfrage verwenden:
query { authors (country: “Nigeria”) { country, posts { title } } }
Was zurückkehren sollte
[ { country: “Nigeria”, posts: [{...}, {...}, {...}] } ]
Es können auch verschachtelte Felder abgefragt werden, wie bei den Beiträgen mit dem Post-Typ können Sie nur nach den Titeln fragen:
query { authors(country: 'Nigeria') { country, posts { title } } }
Und es sollte jeden Autorentyp zurückgeben, der mit Nigeria übereinstimmt, das das Land und das Post-Array zurückgibt, das Objekte mit nur dem Titelfeld enthält.
Gatsby mit GraphQL
Um den Overhead eines Servers/Dienstes zu vermeiden, der Daten bereitstellt, die GraphQL transformieren kann, führt Gatsby GraphQL-Abfragen zur Erstellungszeit aus. Daten werden den Komponenten während des Build-Prozesses bereitgestellt, sodass sie im Browser ohne Server verfügbar sind.
Dennoch kann Gatsby als Server ausgeführt werden, der von anderen GraphQL-Clients wie GraphiQL in einem Browser abgefragt werden kann.
Gatsby Möglichkeiten zur Interaktion mit GraphQL
Es gibt zwei Stellen, an denen Gatsby mit GraphQL interagieren kann, über eine gatsby-node.js-API-Datei und über Seitenkomponenten.
gatsby-node.js
Die createPage-API kann als Funktion konfiguriert werden, die einen graphql
als Teil der Elemente im ersten Argument erhält, das an die Funktion übergeben wird.
// 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 } } } } }`) }
Im obigen Code haben wir den GraphQL-Hilfsdienst verwendet, um Markdown-Dateien aus Gatsbys Datenschicht abzurufen. Und wir können dies einfügen, um eine Seite zu erstellen und vorhandene Daten innerhalb der Gatsby-Datenschicht zu ändern.
Seitenkomponenten
Seitenkomponenten innerhalb des Verzeichnisses /pages oder Vorlagen, die von der API-Aktion createPage
gerendert werden, können graphql
aus dem gatsby
-Modul importieren und eine pageQuery
exportieren. Gatsby wiederum würde neue Requisitendaten in die Requisiten der Seitenkomponente einfügen, die die aufgelösten data
enthält.
import React from "react"; import { graphql } from "gatsby"; const Page = props => { return
{JSON.stringify(props.data)}; }; export const pageQuery = graphql` Anfrage { ... } `; Standardseite exportieren;
In anderen Komponenten
Andere Komponenten können graphql
und StaticQuery
Komponenten aus dem gatsby
-Modul importieren, die <StaticQuery/>
übergebenden Abfrage-Props rendern, die den Graphql-Helfer implementieren, und rendern, um die zurückgegebenen Daten zu erhalten.
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;
Aufbau eines modernen und fortschrittlichen Gatsby-Publishing-Blogs
In diesem Abschnitt werden wir durch einen Prozess zum Erstellen eines Blogs gehen, der Tagging, Kategorisierung, Paginierung und Gruppierung von Artikeln nach Autoren unterstützt. Wir werden Plugins des Gatsby-Ökosystems verwenden, um einige Funktionen einzubringen, und Logiken in GraphQL-Abfragen verwenden, um einen Blog eines Herausgebers zu erstellen, der für Veröffentlichungen mehrerer Autoren bereit ist.
Die endgültige Version des Blogs, den wir erstellen werden, finden Sie hier, auch der Code wird auf Github gehostet.
Initialisieren des Projekts
Wie jede Gatsby-Website initialisieren wir von einem Starter aus, hier verwenden wir den erweiterten Starter, der jedoch an unseren Anwendungsfall angepasst ist.
Klonen Sie zuerst dieses Github-Repo, ändern Sie den Arbeitszweig in dev-init und führen Sie dann npm run develop
development aus dem Ordner des Projekts aus, um den Entwicklungsserver zu starten und die Site unter https://localhost:8000 verfügbar zu machen.
git clone [email protected]:limistah/modern-gatsby-starter.git cd modern-gatsby-starter git checkout dev-init npm install npm run develop
Beim Aufrufen von https://localhost:8000 wird die Standardhomepage für diesen Zweig angezeigt.
Erstellen von Inhalten für Blogbeiträge
Auf einige im Projekt-Repository enthaltene Post-Inhalte kann im dev-blog-content-Zweig zugegriffen werden. Die Organisation des Inhaltsverzeichnisses sieht wie folgt aus: /content/YYYY_MM/DD.md
, in dem Beiträge nach dem erstellten Monat eines Jahres gruppiert werden.
Der Inhalt des Blogposts hat title
, date
, author
, category
, tags
als Titel, die wir verwenden, um einen Post zu unterscheiden und weiter zu verarbeiten, während der Rest des Inhalts der Hauptteil des Posts ist.
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.
Anzeigen von Beitragsinhalten
Bevor wir unsere Markdown-Beiträge in HTML rendern können, müssen wir einige Verarbeitungsschritte durchführen. Laden Sie zuerst die Dateien in den Gatsby-Speicher, analysieren Sie die MD in HTML, verknüpfen Sie Bildabhängigkeiten und Likes. Um dies zu vereinfachen, werden wir eine Vielzahl von Plugins des Gatsby-Ökosystems verwenden.
Wir können diese Plugins verwenden, indem wir die gatsby-config.js im Stammverzeichnis des Projekts so aktualisieren, dass sie wie folgt aussieht:
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", ], }, }, ], };
Wir haben Gatsby angewiesen, die Plugins einzuschließen, um uns bei der Durchführung einiger Aktionen zu unterstützen, insbesondere beim Abrufen von Dateien aus dem /static-Ordner für statische Dateien und /content für unsere Blog-Beiträge. Außerdem haben wir ein Plugin zur Umwandlung von Bemerkungen hinzugefügt, um alle Dateien, die mit .md oder .markdown enden, in einen Knoten mit allen Bemerkungsfeldern umzuwandeln, um Markdown als HTML zu rendern.
Schließlich haben wir Plugins in den Betrieb auf den von gatsby-transformer-remark
generierten Knoten aufgenommen.
Implementieren der API-Datei gatsby-config.js
In Zukunft können wir innerhalb von gatsby-node.js im Projektstamm eine Funktion namens createPage
und den Inhalt der Funktion verwenden, um den graphQL-Helfer zu verwenden, um Knoten aus der Inhaltsebene von GatsbyJS zu ziehen.
Die erste Aktualisierung dieser Seite würde beinhalten, sicherzustellen, dass wir einen Slug-Satz für die MarkDown-Bemerkungsknoten haben. Wir hören auf die onCreateNode-API und lassen den Knoten erstellen, um festzustellen, ob es sich um eine Art MarkdownRemark handelt, bevor wir den Knoten aktualisieren, um einen Slug und ein entsprechendes Datum einzuschließen.
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 }); } };
Die Post-Liste
An diesem Punkt können wir die createPages
API implementieren, um alle Markdowns abzufragen und eine Seite mit dem Pfad als Slug zu erstellen, den wir oben erstellt haben. Sehen Sie es auf 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, }); } };
In der createPages
Funktion verwenden wir den von Gatsby bereitgestellten graphql
Helfer, um Daten aus der Inhaltsschicht abzufragen. Wir haben dazu eine standardmäßige Graphql-Abfrage verwendet und eine Abfrage übergeben, um Inhalte vom Typ allMarkdownRemark
. Bewegen Sie sich dann nach vorne, um die Beiträge nach dem Erstellungsdatum zu sortieren.
Wir haben dann eine postPerPage
Eigenschaft aus einem importierten Konfigurationsobjekt gezogen, die verwendet wird, um die Gesamtzahl der Beiträge auf die angegebene Anzahl von Beiträgen für eine einzelne Seite zu reduzieren.
Um eine Auflistungsseite zu erstellen, die Paginierung unterstützt, müssen wir das Limit, die Seitennummer und die Anzahl der zu überspringenden Seiten an die Komponente übergeben, die die Liste darstellen würde. Dies erreichen wir mit der Context-Eigenschaft des createPage
Konfigurationsobjekts. Wir werden auf diese Eigenschaften von der Seite aus zugreifen, um eine weitere graphql-Abfrage durchzuführen, um Beiträge innerhalb des Limits abzurufen.
Wir können auch feststellen, dass wir dieselbe Vorlagenkomponente für die Auflistung verwenden und sich nur der Pfad ändert, indem der Index des Chunk-Arrays verwendet wird, das wir zuvor definiert hatten. Gatsby übergibt die erforderlichen Daten für eine bestimmte URL, die mit /{chunkIndex}
, sodass wir /
für die ersten zehn Posts und /2
für die nächsten zehn Posts haben können.
Beitragsliste rendern
Die Komponente, die diese Seiten rendert, kann unter src/templates/singlePost/index.js
des Projektordners gefunden werden. Es exportiert auch einen graphql
Helfer, der das Limit und die Seitenabfrageparameter, die es vom createPages-Prozess erhalten hat, abruft, um Gatsby nach Posts innerhalb des Bereichs der aktuellen Seite abzufragen.
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 } } } } } `;
Die Beitragsseite
Um den Inhalt einer Seite anzuzeigen, müssen wir die Seite programmgesteuert in der API-Datei gatsby-node.js
erstellen. Zuerst müssen wir eine neue Komponente definieren, mit der der Inhalt gerendert wird, dafür haben wir 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 } } } `;
Auch hier verwenden wir einen graphQL-Helfer, um eine Seite durch eine Slug-Abfrage herauszuziehen, die über die createPages-API an die Seite gesendet würde.
Als nächstes sollten wir den folgenden Code am Ende der createPages
-API-Funktion zu gatsby-node.js hinzufügen.
// 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, }, }); });
Und wir könnten „/{pageSlug}“ besuchen und den Inhalt der Markdown-Datei für diese Seite als HTML rendern lassen. Als Beispiel sollte https://localhost:8000/the-butterfly-of-the-edge das konvertierte HTML für den Markdown laden unter: content/2020_05/01.md
, ähnlich wie bei allen gültigen Slugs. Toll!
Rendern von Kategorien und Tags
Die einzelne Beitragsvorlagenkomponente hat einen Link zu einer Seite im Format /categories/{categoryName}
, um Beiträge mit ähnlichen Kategorien aufzulisten.
Wir können zuerst alle Kategorien und Tags erfassen, während wir die einzelne Beitragsseite in der Datei gatsby-node.js
erstellen, und dann Seiten für jede erfasste Kategorie/jedes erfasste Tag erstellen, indem wir den Kategorie-/Tag-Namen übergeben.
Eine Änderung des Abschnitts zum Erstellen einer einzelnen Beitragsseite in gatsby-node.js sieht folgendermaßen aus:
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, }, }); });
Und innerhalb der Komponente zum Auflisten von Posts nach Tags können wir die pageQuery
Exportabfrage graphql für Posts haben, einschließlich dieses Tags in seiner Tag-Liste. Dazu verwenden wir die filter
von graphql und den $in-Operator:
// 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 } } } } } `;
Und wir haben den gleichen Prozess in der Kategorieauflistungskomponente, und der Unterschied besteht darin, dass wir nur herausfinden müssen, wo die Kategorien genau mit dem übereinstimmen, was wir ihr übergeben.
// 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 } } } } } `;
Bemerkenswerterweise rendern wir innerhalb der Tags- und Kategoriekomponenten Links zu der einzelnen Beitragsseite, um den Inhalt eines Beitrags weiter zu lesen.
Unterstützung für Autoren hinzufügen
Um mehrere Autoren zu unterstützen, müssen wir einige Änderungen an unseren Beitragsinhalten vornehmen und neue Konzepte einführen.
Laden Sie JSON-Dateien
Zunächst sollten wir in der Lage sein, den Inhalt von Autoren in einer JSON-Datei wie dieser zu speichern:
{ "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" } ] }
Wir würden sie in einem Autorenverzeichnis im Stammverzeichnis unseres Projekts als /authors
speichern. Beachten Sie, dass der Autor-JSON über mdField
verfügt, das die eindeutige Kennung für das Autorenfeld wäre, das wir in den Markdown-Blog-Inhalt einführen werden. Dadurch wird sichergestellt, dass Autoren mehrere Profile haben können.
Als nächstes müssen wir die Plugins gatsby-config.js
aktualisieren, indem wir gatsby-source-filesystem
, den Inhalt aus dem Verzeichnis authors/
in den Files Node zu laden.
// gatsby-config.js { resolve: `gatsby-source-filesystem`, options: { name: "authors", path: `${__dirname}/authors/`, }, }
Zuletzt werden wir gatsby-transform-json
installieren, um JSON-Dateien umzuwandeln, die für eine einfache Handhabung und ordnungsgemäße Verarbeitung erstellt wurden.
npm install gatsby-transformer-json --save
Und fügen Sie es in die Plugins von gatsby-config.js
,
module.exports = { plugins: [ // ...other plugins `gatsby-transformer-json` ], };
Seite „Autoren abfragen und erstellen“.
Zunächst müssen wir alle Autoren in unserem authors/
-Verzeichnis innerhalb von gatsby-config.js
, die in die Datenschicht geladen wurden, wir sollten den folgenden Code an die createPages
API-Funktion anhängen
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, }, }); });
In diesem Snippet ziehen wir alle Autoren aus dem Typ allAuthorsJson und rufen dann forEach auf den Knoten auf, um eine Seite zu erstellen, auf der wir das mdField
, um den Autor und die authorDetails
für vollständige Informationen über den Autor zu unterscheiden.
Rendern von Beiträgen des Autors
In der Komponente, die die Seite rendert, die unter src/templates/authorsListing/index.jsx
zu finden ist, haben wir den folgenden Inhalt für die Datei
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 } } } } } `;
Im obigen Code haben wir die pageQuery
so exportiert, wie wir es tun, um eine GraphQL-Abfrage zum Abrufen von Beiträgen zu erstellen, die mit einem Autor übereinstimmen. Wir verwenden den $eq
Operator, um dies zu erreichen und Links zu einer einzelnen Beitragsseite zum weiteren Lesen zu generieren.
Fazit
In Gatsby können wir alle Daten, die innerhalb seiner Datenzugriffsschicht vorhanden sind, mithilfe der GraphQL-Abfrage abfragen und Variablen mithilfe einiger Konstrukte weitergeben, die durch die Architektur von Gatsby definiert sind. Wir haben gesehen, wie wir den graphql
Helfer an verschiedenen Stellen einsetzen und weit verbreitete Muster für die Abfrage von Daten in Gatsbys Websites mit Hilfe von GraphQL verstehen können.
GraphQL ist sehr leistungsfähig und könnte andere Dinge wie Datenmutation auf einem Server erledigen. Gatsby muss seine Daten zur Laufzeit nicht aktualisieren, daher unterstützt es die Mutationsfunktion von GraphQL nicht.
GraphQL ist eine großartige Technologie, und Gatsby macht es sehr interessant, sie in ihrem Rahmen zu verwenden.
Verweise
- Gatsby-Unterstützung für GraphQL
- Warum Gatsby GraphQL verwendet
- GraphQL-Konzepte in Gatsby
- How To GraphQL: Grundlegende Konzepte
- Schemadefinitionssprache in GraphQL
- Eine Einführung in GraphQL
- Gatsby Advanced Starter