iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 20
0

昨天我們完成了 Slug 的添加跟靜態資料的讀取,今天我們要建立一個頁面模板來動態的創建頁面,話不多說,就直接來進入主題吧!

使用 createPages 來動態創建頁面

昨天我們已經在 gatsby-node.js 中新增不少程式碼,我們今天就接續著往下新增,我們先命名一個變數 basePath 並 assign 根目錄作為它的 value,接著我們使用 createPages 來建立頁面。

這邊要注意一下,我們元件還沒有新增,只是先暫時設一個路徑,因為我們要先嘗試 Query 資料,並對資料做一些處理,同樣的,我們也要對 Query 失敗來做些處理。

exports.createPages = async ({ actions, graphql, reporter }) => {
  const basePath = "/"
  actions.createPage({
    path: basePath,
    component: require.resolve("./src/templates/events.js"),
  })
}

查詢事件的處理

首先,我們要先查詢所有的資料,並且我們設定按照開始的日期去做排序,如果有出現錯誤的話,我們就直接處理掉它。

const result = await graphql(`
    query {
      allEvent(sort: { fields: startDate, order: ASC }) {
        nodes {
          id
          slug
        }
      }
    }
  `)
  if (result.errors) {
    reporter.panic("error loading events", result.errors)
    return
  }

接著,我們將查詢到的資料來跑迴圈,最後利用 createPage 函式來創建頁面。

最後,我們要把剛剛先設定路徑的元件來補齊,所以我們在 gatsby-theme-events 工作區內 新增一個 src 資料夾,並在資料夾內再新增一個 templates 資料夾,然後在裡面放一個 events.js。

這時,你的資料夾結構應該會長得如下圖一樣。

https://ithelp.ithome.com.tw/upload/images/20201005/20109495C37P2iF350.png

再來我們快速的建立一個簡單的元件,所以我們將以下程式碼放入 events.js 中

import React from 'react'

const EventTemplate = () => {
  return (
    <p>TODO: Build the event page template</p>
  )
}

export default EventTemplate

完成後,我們來測試一下頁面是否有成功的被建立起來,我們運行下面的指令來開啟開發伺服器

yarn workspace gatsby-theme-events develop

我們輸入 http://localhost:8000/404 來連結到 Gatsby 提供的 404 畫面,來看畫面是否有成功創建,現在畫面上面應該會有首頁加上你 data 內的資料筆數,例如下圖紅框處所示,讀者們可以試著點擊看看,是否能成功連到對應頁面。

https://ithelp.ithome.com.tw/upload/images/20201005/20109495YjIkVPaoX9.png

而如果我們要在元件本身顯示數據的話,我們還需要用到 useStaticQuery 來幫助我們做 Query,所以我們要在 events.js 中先引入 graphql 與 useStaticQuery,接著在元件內執行我們要的 Query,你的程式碼應該會如下

https://ithelp.ithome.com.tw/upload/images/20201005/20109495S1XFLTGQoe.png

建立通用的 Layout Component

接著,我們在 Gatsby-theme-events 工作區下的 src 資料夾內建立一個資料夾,名稱為 components 並在其中再建立一支 layout.js。

Layout 裡面我們接受上層傳來的 props 並解構其中的 children

import React from 'react'

const Layout = ({children}) => {
  return (
    <div>
      <h1> ITHelp Gatsby Custom Theme</h1>
      {children}
    </div>
  )
}

export default Layout

現在,我們還需要一個 list 頁面,所以同樣的,我們在 components 資料夾下再建立一支 event-list.js,裡面也是接受 props 傳來的值並解構出來做使用。

import React from 'react'

const EventList = ({events}) => {
  return (

    <pre>{JSON.stringify(events, null, 2)}</pre>

  )
}

export default EventList

將建立好的組件添加至頁面中

完成以上兩個通用元件後,我們將其引入至 templates 的 events.js 中,

import Layout from "../components/Layout"
import EventList from "../components/EventList"

接著,我們在 return 的 JSX 中調整成我們剛剛做好的元件

<Layout>
   <EventList events={events} />
</Layout>

最後,我們重啟開發伺服器來看看吧!

https://ithelp.ithome.com.tw/upload/images/20201005/20109495FFvNFe6gUJ.png

讀者們應該能成功地看到剛剛我們在 Layout 中打的標題與子元件 EventList 接到 Props 傳來的值。

但我們可不能就這樣呈現給使用者觀看,所以我們要來調整一下 List 的 HTML 結構,來讓我們能將查詢出來的值放到對應的位置當中。

首先我們需要對 events 來跑迴圈,建立多個 tag li,並給他一個屬性為 key,key 裡面我們會放入獨一無二的值,也就是我們的 ID,接著,我們要給這些活動連結,而網址恰好就是我們之前塞入的 Slug,連結名稱就是 name,最後我們再對時間做一些處理後,即可回到我們的瀏覽器看看結果囉!

import React from "react"
import { Link } from "gatsby"
const EventList = ({ events }) => (
  <>
    <h2>Upcoming Events</h2>
    <ul>
      {events.map(event => (
        <li key={event.id}>
          <strong>
            <Link to={event.slug}>{event.name}</Link>
          </strong>
          <br />
          {new Date(event.startDate).toLocaleDateString("en-US", {
            month: "long",
            day: "numeric",
            year: "numeric",
          })}{" "}
          in {event.location}
        </li>
      ))}
    </ul>
  </>
)

export default EventList

讀者們如果看到如下圖一般,代表說已經改寫成功啦,我們成功地把資料一一都放到頁面上囉

https://ithelp.ithome.com.tw/upload/images/20201005/20109495GaCu2lnfdk.png

但細心的讀者,會發現,奇怪,怎麼點連結下去還是一樣的畫面?
沒錯,我們今天的尾聲就是要再來創立內頁模板,
所以我們先在 components 與 templates 底下新增一個 Event.js,
首先,我們先來看 Templates 底下的 Event.js,裡頭我們會用 ID 來 Query 單篇文章的資料,且由於是頁面,所以我們可以直接用 graphql 來進行查詢。

查詢完畢後,我們會將查詢到的資料,利用 Props 與解構賦值的方式來傳遞給 components 裡的 Event.js,所以我們 templates/event.js 的程式碼會長得如下面這般

import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"
import Event from "../components/event"

export const query = graphql`
  query($eventID: String!) {
    event(id: { eq: $eventID }) {
      name
      url
      startDate(formatString: "MMMM DD YYYY")
      endDate(formatString: "MMMM DD YYYY")
      location
      slug
    }
  }
`
const EventTemplate = ({ data: { event } }) => (
  <Layout>
    <Event {...event} />
  </Layout>
)

export default EventTemplate

而在 components/event.js 中,我們會接由上層傳下來的 Props 作為資料

import React from 'react'
const Event = ({ name, location, url, startDate, endDate }) => (
  <div>
    <h2>
      {name} ({location})
    </h2>
    <p>
      {startDate}-{endDate}
    </p>
    <p>
      網址: <a href={url}>{url}</a>
    </p>
  </div>
)
export default Event

完成後,同樣的我們重啟開發伺服器來看看吧!

https://ithelp.ithome.com.tw/upload/images/20201005/20109495hU2SCInsR7.png

這時讀者們應該都能順利進到內頁當中了!
今天大家都順利的將資料轉成列表頁、內頁,
而明天我們要來為主題增加一些樣式,希望能在兩章以內結束建立自己主題的篇章。

參考資料

Gatsby - building a Theme


上一篇
[Day 19] - 建立屬於自己的主題 ( 二 )
下一篇
[Day 21] - 建立屬於自己的主題 ( 四 )
系列文
雖然你不是木村拓哉,但它也可以讓你變很行 - Gatsby.js30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言