ตอนที่ 5 - Data Fetching และการดึงข้อมูลจาก API

Published on

เขียนวันที่ : July 15, 2022

Discord

ตอนนี้จะเป็นเรื่องของ Fetching API เพื่อดึงข้อมูลจาก API มาแสดง ซึ่งจริงๆ แล้ว fetching data นั้นทำได้หลายท่ามากๆ เช่น

  • Client Side - ด้วยการใช้ useEffect() และทำการ fetch แบบเดียวกับท่า React.js ธรรมดาครับ
  • Server Side - ด้วย getServerSideProps จะทำการ fetch data ทุกๆ ครั้งที่มีการเรียก request (รันที่ server)
  • Hybrid - ทั้ง Incremental Static Regenration (ISR) และ Static Site Generation (SSG)

ซึ่งแบบ Client Side เราจะขอข้ามไปนะครับ จะพูดถึงเฉพาะที่ใช้ใน Next.js เท่านั้น

getServerSideProps

  • เป็นการ fetch ข้อมูลฝั่ง Server คือจะทำการ fetch api ทุกๆครั้ง ที่เราทำการ request หน้าเว็บนั้นๆ
  • return เป็น JSON เพื่อใช้สำหรับ pre-render Page (จะเป็นค่า props ที่ให้เราเรียกใช้งานใน component)

ตัวอย่างการใช้งาน เช่น ผมสร้างไฟล์ hello.js ขึ้นมา ใน pages

pages/hello.js
function Hello({ title }) {
  return <p>{title}</p>
}

export async function getServerSideProps(context) {
  return {
    props: { title: 'This is title from getServerSideProps' },
  }
}

export default Hello

ลอง start server

yarn dev

และดูผลลัพธ์ครับ http://localhost:3000/hello

getStaticProps

getStaticProps หรือ Static Site Generation ตัว Next.js จะทำการ pre-render หน้า page โดยใช้ props ที่ return จาก getStaticProps ครับ

export async function getStaticProps(context) {
  return {
    props: {}
  }
}
  • ใช้ getStaticProps เมื่อเราต้องการ data จาก API
  • เมื่อต้องการ pre-render เพื่อรองรับ SEO
  • ตัว getStaticProps รันฝั่ง Server (ตอน build time) หรือรัน background ถ้าเราใช้ revalidate

ตัวอย่างการใช้ getStaticProps เพื่อดึงข้อมูล API ตัวอย่าง ผมทำการ fetch api posts จาก https://jsonplaceholder.typicode.com/posts และก็ return props ไปให้ Posts ใช้เพื่อ render html ครับ

pages/posts.js
function Posts({ posts }) {
  return (
    <div>
      <h2>Posts</h2>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  )
}

export async function getStaticProps() {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },
  }
}

export default Posts

Incremental Static Regeneration (ISR)

จริงๆ มันก็คือการใช้ getStaticProps ที่เป็นเวอร์ชั่น upgrade ครับ โดยการเพิ่ม option revalidate การทำงานของมันคือ ปกติ getStaticProps จะทำงานแค่ Server side เวลา request จะไม่รันแล้ว นอกจาก เราจะใส่ revalidate ตัว Next.js จะทำการ trigger และทำการ rebuild (หรือเรียก getStaticProps ให้เราเอง เป็น Background process)

ตัวอย่าง เดิมของ getStaticProps แต่เพิ่ม revalidate ให้มัน ทำการ refresh ทุกๆ 5วิ โดยผมตั้งชื่อให้มันว่า meow.js

pages/meow.js
import Image from 'next/image'

function Meow({ meow }) {
  return (
    <div>
      <h2>Meow</h2>
      <Image src={meow.url} width="300" height="300" alt={meow.file} />
    </div>
  )
}

export async function getStaticProps() {
  const res = await fetch('https://meow.senither.com/v1/random')
  const response = await res.json()

  return {
    props: {
      meow: response.data,
    },
    revalidate: 5,
  }
}

export default Meow

เนื่องจากตัวอย่าง ผมใช้ <Image> ของ Next.js เพื่อ render image ซึ่งตัว url มาจากเว็บ meow.senither ตัว default ของ Next ไม่สามารถ hotlink ได้ครับ ต้องทำการเพิ่มใน next.config.js ก่อน

next.config.js
module.exports = {
  images: {
    domains: ['meow.senither.com'],
  },
}

วิธีทดสอบคือ เราต้องทำการ build ก่อนครับ (เพราะว่า yarn dev มันจะเรียก getStaticProps ทุกๆครั้งที่ request เลยเทสไม่ได้ ต้อง build เพื่อให้เป็น production mode) ซึ่งเวลาเรารัน build

yarn build

เราจะเห็นผลลัพธ์หน้า pages ของเรา ว่าเป็น ISR และมี revalidate กี่วินาทีบอกไว้ ประมาณนี้

├ ● /meow (ISR: 5 Seconds) (430 ms)        354 B          83.4 kB

จากนั้นสั่ง

yarn start

เข้าหน้าเว็บ http://localhost:3000/meow จากนั้น refresh รัวๆ จะเห็นว่ามันจะได้รูปเดิม (เพราะว่าถูก build ครั้งแรก) จนกว่าจะครบ 5วิ มันก็จะเรียก getStaticProps และก็จะได้รูปใหม่ ไปเรื่อยๆ ทุกๆ 5 วิ

🎉 จบแล้วครับ สำหรับตอนที่ 5 - เรื่องของ Data Fetching เบื้องต้นก็มีประมาณนี้ครับ เดี๋ยวในตอนต่อไป จะพูดถึง Dynamic Routes เราก็จะได้ใช้ Data Fetching เพื่อให้เห็นภาพจริงๆมากขึ้น รวมถึง getStaticPaths ที่ยังไม่ได้พูดไปด้วยครับ

คำถาม

  • ถ้า getServerSideProps render แล้ว error ตัว Next.js จะ show หน้าไหน (ไฟล์ไหน)?
  • เราสามารถ cached Server-Side Rendering ได้มั้ย ถ้าได้ทำยังไง?
  • getStaticProps สามารถ export หน้าอื่นๆ เช่น components หรือ _app หรือ _document ได้มั้ย?
Discord