Bookmarks

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

  • 拥抱 Gatsby,用 React 搭建完整博客系统(二)—— 从本地文件获取数据

  • 前言

    在本系列文章的第一篇中,我们已经成功搭建了我们的 Gatsby 网站。我们可以随意的使用 React 为网站添加页面,但我们的网站不可能完全依赖于我们手写每一个页面,我们需要外部数据的参与。

    本篇内容就将讲述如何让 Gatsby 读取到本地文件,我们的目标是从本地读取文件,并将文件列表展示在页面中,在实现这一目标之前,我们必须一起学习一些必要的知识。

    Gatsby 中的数据

    在 Gatsby 中的数据,可以简单理解为“所有在 React 组件之外的东西”。

    数据可以是任何来源的,可以来自于本地文件,可以来自于 Wordpress 或者 Strapi 等提供的 API。即便是本地文件,也可以是任何格式,可以是 Markdown 文档,也可以是 CSV 数据————当然这里有一个前提,你要能找到特定的插件来解析你需要的文件。

    我们可以以 Webpack 中 loader 的概念来类比,Webpack 可以解析任何文件——如果有支持这一扩展名的 loader 的话。

    使用 GraphQL

    Gatsby 的数据层由 GraphQL 驱动,有兴趣学习 GraphQL 可以前往官方文档中推荐的网站:如何学习 GraphQL

    GraphQL 并非必须使用,如果你要搭建的网站内容非常简单,可以选择直接使用 createPage API 将数据提取到页面,官方提供了一个不使用 GraphQL 的示例,可供参考,但本文将坚定不移的使用 GraphQL 这一面向未来的技术,下面就简单看一下如何在 Gatsby 中进行 GraphQL 查询。

    在页面中查询

    还记得我们在上文中展示的 GraphQL Explorer 的截图吗?
    gatsby-from-zero-1-4.png

    我们发起了一个查询,查询了站点元数据(存储在 gatsby-config.js 中)的网站标题和网站简介,我们就利用这一查询得到的数据来生成一个新的 about 页面。

    pages 目录下创建 about.js 文件,内容如下:

    import React from "react"
    import { Link } from "gatsby"
    
    import Layout from "../components/layout"
    
    const About = ({data}) => (
      <Layout>
        <h1>About {data.site.siteMetadata.title}</h1> {/* highlight-line */}
        <p>
          {data.site.siteMetadata.description}
        </p>
        <Link to="/">Go back to the homepage</Link>
      </Layout>
    )
    
    export default About
    
    export const query = graphql`
      query {
        site {
          siteMetadata {
            title
            description
          }
        }
      }
    `
    

    之后打开http://localhost:8000/about,就能看到我们已经成功将数据渲染到了页面中。

    gatsby-from-zero-2-1.png

    从上面页面的内容可以看出,页面查询定义在组件之外(一般在页面组件文件的最后),并且只在页面组件中可用,GraphQL 查询的加入没有破坏 React 文件的结构,这非常好。

    在非页面中查询

    在非页面中查询是需要使用 Gatsby 提供的 StaticQuery 特性,在 React Hooks 日趋成为主流的情况下,Gatsby 也提供了 useStaticQuery 强化了这一特性,本文均将使用最新的 useStaticQuery 语法。

    新旧两种写法的对比可以查看官方文档,新写法与页面查询更加一致。

    我们同样以查询页面标题和说明为例,展示一下 useStaticQuery 的使用,查看我们使用的示例中的 /src/components/layout.js 文件内容:

    import React from "react"
    import PropTypes from "prop-types"
    import { useStaticQuery, graphql } from "gatsby"
    
    import Header from "./header"
    import "./layout.css"
    
    const Layout = ({ children }) => {
      const data = useStaticQuery(graphql`
        query SiteTitleQuery {
          site {
            siteMetadata {
              title
            }
          }
        }
      `)
    
      return (
        <>
          <Header siteTitle={data.site.siteMetadata.title} />
          <div
            style={{
              margin: `0 auto`,
              maxWidth: 960,
              padding: `0px 1.0875rem 1.45rem`,
              paddingTop: 0,
            }}
          >
            <main>{children}</main>
            <footer>
              © {new Date().getFullYear()}, Built with
              {` `}
              <a href="https://www.gatsbyjs.org">Gatsby</a>
            </footer>
          </div>
        </>
      )
    }
    
    Layout.propTypes = {
      children: PropTypes.node.isRequired,
    }
    
    export default Layout
    

    可以注意到,这一页面使用了 useStaticQuery,可以很明显的看到,与页面查询不同的是,必须将查询语句通过 useStaticQuery 包裹,并且写在组件内部,不过整体仍不失清晰。

    在页面中同样可以使用 useStaticQuery,可以让你的页面看起来更 React 一些。

    使用 GraphiQL Explorer

    GraphiQL Explorer 是 GraphQL 提供的一款资源可视化查询工具,可以检查 GraphQL 的语法,发送 GraphQL 的请求,还提供文档查询等功能。Github 最新的 v4 版本的 API 就全面转向了 GraphQL,可以访问这里体验,Gatsby 运行时同样运行了一个 GraphiQL Explorer 实例,可以通过访问 http://localhost:8000/__graphql 体验。

    读者可以通过这一工具来体验一下 GraphQL 的使用。

    读取本地文件内容

    借助于 Gatsby 强大的插件,要实现这一功能非常简单,简而言之:使用 gatsby-source-filesystem 插件将本地文件转换为 Gatsby 数据,用户直接通过 GraphQL 查询数据进行使用。

    安装配置 gatsby-source-filesystem 插件

    使用 yarn add gatsby-source-filestystem 安装插件,之后我们在 gatsby-config.js 文件中进行配置。

    将以下代码添加到 gatsby-config.js 文件中的 plugins 数组中:

      {
          resolve: `gatsby-source-filesystem`,
          options: {
            name: `src`,
            path: `${__dirname}/src/`,
          },
        },
    

    我们使用的起始模板中,已经包括了 gatsby-source-filesystem 插件,不过只解析了 /src/images 目录,我们再后面添加解析 /src 目录,就可以获取到全部文件了。

    由于代码中依赖对 images 目录的解析,这里不直接修改目录,而是增加目录,gatsby-source-filesystem 可以分别解析多个目录。

    重新启动开发服务器,前往 GraphiQL Explorer 中查询,可以看到 src 目录中所有文件都已经在数据源中了:

    gatsby-from-zero-2-2-with-filesystem.png

    使用 gatsby-source-filesystem 插件

    我们创建一个页面,来展示一下我们 src 目录下都有哪些文件,我们直接参考官方示例,要展示的字段可以根据 GraphiQL 中查询到的信息任意替换。

    import React from "react"
    import { graphql } from "gatsby"
    import Layout from "../components/layout"
    
    export default ({ data }) => {
      console.log(data)
      return (
        <Layout>
          <div>
            <h1>My Site's Files</h1>
            <table>
              <thead>
                <tr>
                  <th>relativePath</th>
                  <th>prettySize</th>
                  <th>extension</th>
                  <th>birthTime</th>
                </tr>
              </thead>
              <tbody>
                {data.allFile.edges.map(({ node }, index) => (
                  <tr key={index}>
                    <td>{node.relativePath}</td>
                    <td>{node.prettySize}</td>
                    <td>{node.extension}</td>
                    <td>{node.birthTime}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </Layout>
      )
    }
    
    export const query = graphql`
      query {
        allFile {
          edges {
            node {
              relativePath
              prettySize
              extension
              birthTime(fromNow: true)
            }
          }
        }
      }
    `
    

    打开 http://locahost/my-files页面,就可以看到效果:

    gatsby-from-zero-2-3-my-files.png

    总结

    通过本篇内容,我们了解了 Gatsby 中的数据,并且了解了如何获取项目目录中的文件,但目前只有文件本身的信息,却无法获取文件内容,要获取文件内容并将其转换为数据源,就需要数据源转换插件的帮助了,下一部分我们就将实现这一功能。