iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

0

今天實作首頁的顯示舊文章的按鈕功能。

在實作前想先介紹react的hook這個東西:
在去年以前,react的組件實作都是使用Class component,也就是以class的方式來定義組件,
而如果使用function的方式的話,則是Function component。

function component雖然好用,但卻有著無法使用state和生命週期函式的問題,因此又稱為無狀態組件。

但class component卻有著一些問題,例如會讓組件結構變得複雜以及以及不好管理,以及無法紀錄某個瞬間的組件狀態,因此才有了hook的出現。
hook這個工具允許我們以function component來使用state跟生命週期函式,且更可以客製化自己的hook,使得組件的運算邏輯和狀態更加容易管理。

文章中不會有詳細的說明,有興趣的可參閱:

函式組件的確比起類別組件更容易去使用,且不用擔心this綁定的問題,目前官方跟主流都是推薦使用hook+function component去做開發。

因為我們的index.js是使用function component,因此,我將使用useState這個hook,來實作組件的狀態。


用法:
要藉由hook使用state,我們只需要下以下的語法:

const [狀態名, 設定狀態的函式名] = useState(狀態初始值)

這個語法會回傳一個陣列,第一項是我們的state,第二項則是類似原本setState功能的一個函式但用法稍有不同。
原先class component的setState傳入的是一個物件,且可以只傳入部分的key值下去更新,而hook的則不同你只需要傳入一個全新的狀態值即可,且狀態的值跟初始值也不限於物件,因此使用上更自由。

詳細可參考官方教學


先秀出修改完的程式碼:

src/page/index.js

import React, { useState } from "react"
import Layout from "../components/layout"
import PostPreview from "../components/post-preview"

const IndexPage = (props) => {
  /*
    使用useState這個hook,將chunk訂為state,並且setChunk為更改chunk的函式。
    postBoby根據chunk*5的數量來顯示文章,每按一次按鈕,多5篇文章。
  */
  const [chunk, setChunk] = useState(1)
  const head = props.data.allContentfulHead.edges[0].node
  const posts = props.data.allContentfulPost.edges
  const postBoby = posts.slice(0, 5*chunk).map((post)=><PostPreview key={post.node.slug} data={post.node}/>)

  return (
  <Layout>
    <header className="masthead" style={{backgroundImage: `url('${head.image.file.url}')`}}>
      <div className="overlay"></div>
      <div className="container">
        <div className="row">
          <div className="col-lg-8 col-md-10 mx-auto">
            <div className="site-heading">
              <h1>{head.title}</h1>
              <span className="subheading">{head.subTitle}</span>
            </div>
          </div>
        </div>
      </div>
    </header>
    <div className="container">
      <div className="row">
        <div className="col-lg-8 col-md-10 mx-auto">
          {postBoby}
          {/* 根據顯示的文章數是否小於總文章數,來決定按鈕是否顯示 */}
          <div className="clearfix" style={{display: 5*chunk<posts.length ? 'block' : 'none' }}>
            {/* 按下按鈕,觸發setChunk,將chunk變為chunk+1,並且因為state改變,因此組件觸發重新渲染 */}
            <a className="btn btn-primary float-right" onClick={() => setChunk(chunk + 1)}>Older Posts →</a>
          </div>
        </div>
      </div>
    </div>

    <hr/>
  </Layout>
)}

export default IndexPage

export const indexQuery = graphql`
query indexQuery {
  allContentfulHead {
    edges {
      node {
        image {
          file {
            url
          }
        }
        title
        subTitle
      }
    }
  }
  allContentfulPost(sort: { fields: [publishDate], order: DESC }) {
    edges {
      node {
        slug
        title
        subTitle
        publishDate(formatString: "MMMM Do, YYYY")
        author {
          name
        }
        body {
          childMarkdownRemark {
            excerpt
          }
        }
      }
    }
  }
}
`

我們修改了幾個地方:

  • 首先,我們使用了useState這個hook,做出了一個chunk變數(預設值為1),這個變數代表的意思是現在是第幾批顯示的文章,接著使用.slice(0, 5*chunk)去把原先的文章陣列取出5*chunk數的文章做顯示。
  /*
    使用useState這個hook,將chunk訂為state,並且setChunk為更改chunk的函式。
    postBoby根據chunk*5的數量來顯示文章,每按一次按鈕,多5篇文章。
  */
  const [chunk, setChunk] = useState(1)
  const head = props.data.allContentfulHead.edges[0].node
  const posts = props.data.allContentfulPost.edges
  const postBoby = posts.slice(0, 5*chunk).map((post)=><PostPreview key={post.node.slug} data={post.node}/>)
  • 接著,根據文章顯示數(5*chunk)是否小於總文章數(posts.length),來決定是否顯示按鈕,並且,設置事件監聽,當點擊按鈕時,更新chunk並且觸發渲染。
{/* 根據顯示的文章數是否小於總文章數,來決定按鈕是否顯示 */}
<div className="clearfix" style={{display: 5*chunk<posts.length ? 'block' : 'none' }}>
{/* 按下按鈕,觸發setChunk,將chunk變為chunk+1,並且因為state改變,因此組件觸發重新渲染 */}
<a className="btn btn-primary float-right" onClick={() => setChunk(chunk + 1)}>Older Posts →</a>
  • 最後,便是補上之前忘記位文章加上去的排序條件。
allContentfulPost(sort: { fields: [publishDate], order: DESC }) {

如此便完成了更舊文章的功能了!!


點下去
https://ithelp.ithome.com.tw/upload/images/20191031/20111629OGzBNmZjvq.png

成功!
https://ithelp.ithome.com.tw/upload/images/20191031/20111629ikZJBoXP0V.png

github


上一篇
Day25. 部落格實作 (四)
下一篇
Day27. 部落格實作 (END)
系列文
用Gatsby.js做出一個簡單的部落格28

尚未有邦友留言

立即登入留言