Bookmarks

You haven't yet saved any bookmarks. To bookmark a post, just click .

  • 拥抱 Gatsby,用 React 搭建完整博客系统(五)—— 从 Strapi 获取数据并生成页面

  • 前言

    按照之前文章内容,我们已经搭建好了 Strapi 环境,创建了我们网站所需要的内容类型,并添加了测试数据。下一步需要的就是获取 Strapi 中的数据,并使用 Strapi 中的数据渲染页面,本部分内容就将实现这一功能。

    从 Strapi 获取数据

    要从 Strapi 获取数据,我们完全可以通过 GraphQL 查询直接请求 Strapi 接口数据,在后续文章中我们会采用这一方式来实现一些高级功能。但在本部分,我们将借助于 Gatsby 所提供的 Strapi 插件 gatsby-source-strapi 来获取 Strapi 中的数据,具体步骤如下:

    首先安装插件:

    yarn add gatsby-source-strapi
    

    之后在项目根目录下的 gatsby-config 中添加以下内容

    // In your gatsby-config.js
    plugins: [
      {
        resolve: `gatsby-source-strapi`,
        options: {
          apiURL: `http://服务器地址:1337`,
          queryLimit: 1000, // Default to 100
          contentTypes: [`post`, `user`, `tag`],
          // Possibility to login with a strapi user, when content types are not publically available (optional).
          loginData: {
            identifier: "",
            password: "",
          },
        },
      },
    ]
    

    登录信息暂时不需填写,我们暂未应用到需要登录的数据。

    之后重新运行项目,再次查看项目 GraphiQL 资源浏览器,可以看到 Strapi 中的资源已经添加到了数据源中:

    gatsby-from-zero-5-graphiql.png

    使用 Strapi 数据生成页面

    回顾使用本地 Markdown 文件生成页面方式

    在本系列文章第三篇中,我们学习了如何使用本地 Markdown 文件生成页面,基本思路是在 gatsby-node.js 中添加 onCreateNode 方法,根据不同的节点类型进行不同的处理,在发现节点为本地 Markdown 文件时,将根据文件路径生成 slug 并添加至数据源,之后在 createPages 方法中查询所有的 slug 并调用 Gatsby API 为每个 slug 生成页面

    而要生成页面,我们需要提供一个模板文件(如/src/templates/post.js),在生成页面时,将 id 或其他信息传递至模板文件中,在模板文件中使用 GraphQL 查询即可获取到特定数据,渲染出不同页面。

    使用 Strapi 数据生成页面

    在生成页面的思路上,使用 Strapi 数据和使用本地 Markdown 文件是一致的,实际上还更加简单,因为我们不再需要通过获取文件路径来生成 slug ,而是直接查询 GraphQL 数据即可。

    修改 gatsby-node.js 文件

    onCreateNode 方法中,我们之前使用了 gatsby-source-filesystem 插件所提供的 createFilePath 方法生成了 slug,并使用 createNodeField 方法将其添加到了数据源中。查看我们在上一节中所创建的 post 内容类型,我们包括了 url 字段,这一字段就是我们所需要的 slug,所以整个 onCreateNode 方法中的内容我们都不再需要,置空即可,没有直接删除是方便之后添加其他方法:

    exports.onCreateNode = ({ node, getNode, actions }) => {
      if (node.internal.type === `StrapiPost`) {}
    }
    

    继续看下方的 createPages 方法,我们查询了所有的 Markdown 文档的 slug,并为每一个 slug 生成了页面,生成页面时,我们传递了 slug 值至模板文件中,使用 Strapi 数据后,我们对其进行简单调整如下:

    exports.createPages = async ({ graphql, actions }) => {
      const { createPage } = actions
      const result = await graphql(`
        query {
          allStrapiPost {
            edges {
              node {
                id
                url
              }
            }
          }
        }
      `)
    
      result.data.allStrapiPost.edges.forEach(({ node }) => {
        createPage({
          path: node.url,
          component: path.resolve(`./src/templates/post.js`),
          context: {
            // Data passed to context is available
            // in page queries as GraphQL variables.
            id: node.id,
          },
        })
      })
    }
    

    完全参考了使用本地 Markdown 文档时的模式,只不过将页面路径由 slug 换成了 url ,同时向模板文件传递了 id,整体仍然非常清晰。

    修改模板文件

    我们还需要修改模板文件(/src/templates/post.js) 内容,因为查询条件发生了变化,内容结构也发生了变化。

    我们将模板文件修改为如下内容:

    import React from "react"
    import { graphql } from "gatsby"
    import Layout from "../components/layout"
    
    export default ({ data }) => {
      const post = data.strapiPost
      return (
        <Layout>
          <div>
            <h1>{post.title}</h1>
            <div>{post.content}</div>
          </div>
        </Layout>
      )
    }
    
    export const query = graphql`
      query($id: String!) {
        strapiPost(id: {eq: $id}) {
          content
          title
        }
      }
    `
    

    访问我们生成的页面:

    gatsby-from-zero-5-page-no-markdown.png

    你会发现,我们在 Strapi 中添加内容时,content 字段添加的是原始 Markdown 内容,这里并不会将其渲染为 HTML,而是原样输出了,这要怎么办?

    在渲染本地 Markdown 文档时,我们使用了 gatsby-transformer-remark 插件,该插件将本地 Markdown 文档加入数据源时,会生成一个 html 字段,表示的是 Markdown 文档对应的 HTML 内容。而现在我们需要单独的 Markdown 渲染引擎来进行这样的处理,这里我们使用 React-markdown,使用之前先进行安装:

    yarn add react-markdown
    

    插件的使用非常的简单,在页面中引入,并使用组件标签将需要渲染的 Markdown 内容包裹即可,在后期进行页面样式优化时,我们再进一步了解其使用方式。

    初次使用时,发现存在图片过大的问题,经搜索找到了处理方式,在下方所提供的示例文件内容中已经包括

    修改模板文件 /src/templates/post.js 内容:

    import React from "react"
    import { graphql } from "gatsby"
    import Layout from "../components/layout"
    import ReactMarkdown from 'react-markdown'
    
    export default ({ data }) => {
      const Image = props => {
        return <img alt="" {...props} style={{maxWidth: '100%'}} />
      }
      const post = data.strapiPost
      return (
        <Layout>
          <div>
            <h1>{post.title}</h1>
            <ReactMarkdown
              source={post.content}
              renderers={{image: Image}}
            />
          </div>
        </Layout>
      )
    }
    
    export const query = graphql`
      query($id: String!) {
        strapiPost(id: {eq: $id}) {
          content
          title
        }
      }
    `
    

    之后再打开之前的页面,已经一切正常了。

    gatsby-from-zero-5-page-with-markdown.png

    总结

    本部分我们参考之前使用本地 Markdown 文档生成页面的思路实现了使用 Strapi 数据生成页面的功能,现在我们可以通过 Strapi 来管理我们的文章,添加文章后,重新进行构建发布就可以同步数据了,实现了将内容与样式的分离。

    在目前为止,除后台管理功能之外,我们要实现的主体功能已经全部实现,下一部分开始,我们就对我们的网站进行整体规划,并开始撰写样式。