Devahoy Logo

ตอนที่ 4 - เรื่องของ Pre Rendering

Published on

เขียนวันที่ : Jun 19, 2022

สอนเขียนโปรแกรมด้วย Next.js พร้อม Mini Workshop

learn-nextjs/04-pre-rendering
Discord

สวัสดีครับ ตอนที่ 4 มาพูดถึงเรื่องของ Pre Rendering กันครับ บทนี้ส่วนใหญ่เป็นทฤษฎี พยายามอ่านทำความเข้าใจไปก่อนครับ ไม่เข้าใจทั้งหมดไม่เป็นไร รอบทถัดไปเรื่อง Data Fetching เพื่อใช้งานจริงๆ แล้วลองกลับมาอ่านบทนี้อีกทีน่าจะเข้าใจมากขึ้นครับ

Pre-rendering

โดยปกติแล้ว Next.js จะทำการ pre-render ทุกๆหน้าอยู่แล้ว หมายความว่า Next.js จะ generate HTML ของแต่ละหน้าไว้ แทนที่จะเป็นทุกๆอย่าง ทำจาก Client-Side JavaScript (แบบ React ปกติ)

ถ้าเขียน React.js แบบ Client Side เราจะเห็นว่า หน้าเว็บมันจะเห็นแค่ tag <div id="root"></div> แค่นั่น ซึ่งข้อเสียของมันคือ SEO นั่นเอง

ซึ่งพอเป็น Next.js และมี pre-render มาให้ ทำให้เรื่องของ SEO นั่นดีกว่า แบบ client-side

แต่การ Pre-render คือมันไม่ได้โหลดทั้งหมด ทุกๆอย่าง ในหน้านั้นๆนะครับ มันคือการโหลดแค่ที่จำเป็น ที่ต้องใช้ ซึ่งบางทีเค้าก็จะเรียกขั้นตอนนี้ว่าการ hydration

ภาพตัวอย่างเปรียบเทียบ

ภาพตัวอย่างเปรียบเทียบระหว่าง Pre-render และ ไม่ Pre-render (React.js ปกติ) (โดยรูปจาก Learn Next.js)

แบบ No Pre-rendering

No Pre-rendering

จะเห็นว่า เริ่มต้นคือจะเป็นหน้าว่างๆ ขาวๆ ตัว Google Bot มันก็จะเห็นหน้านี้แหละครับ

เทียบกันกับ Pre-rendering กับรูปด้านล่างดูครับ มี HTML (แต่พวก actions ต่างๆ หรือ JavaScript อาจจะยังใช้งานไม่ได้ จนกว่าจะ Hygration จบ หรือโหลดเสร็จ)

Pre-rendering

2 Forms of Pre-rendering

ใน Next.js จะมีการ Pre-rendering หลักๆ คือ Static Generation และ Server-side Rendering** โดยสิ่งที่ต่างกันคือ ขั้นตอนการ generate HTML:

  • Static Generation (แนะนำ) - ตัว HTML จะถูก generate ตอน build time และจะถูก reuse ทุกๆ Request
  • Server-side Rendering - HTML จะถูก generate ทุกๆครั้งที่มี Request

ในโหมด Development yarn dev ทุกๆหน้า จะเป็น Pre-render แบบ Server side แม้ว่า page นั้นจะใช้ Static Generation ก็ตาม

ซึ่งเราสามารถใช้ Static Generation หรือ Server Side รวมๆกัน ในแอพ Next.js เดียวกันได้ เช่น หน้า A, B ใช้ Static Generation แต่ถ้า C และ D ใช้ Server Side ก็ได้

เมื่อไหร่ควรใช้ Static Generation หรือ Server side Rendering

getStaticProps

เราสามารถใช้ Static Generation + fetching Data เพื่อทำการ generate HTML ตอน build time ได้ ด้วยการใช้ getStaticProps

  • getStaticProps จะรันตอน build time โดยใน function getStaticProps เราสามารถ fetch data และ return เป็น props ให้ Component (Page) ได้
  • getStaticProps สามารถ export ได้แค่ใน pages ไม่สาามารถใช้กับไฟล์อื่นๆ ที่ไม่ใช่ page ได้
export default function Home(props) { ... }

export async function getStaticProps() {
  // Get external data from the file system, API, DB, etc.
  const data = ...

  // The value of the `props` key will be
  //  passed to the `Home` component
  return {
    props: ...
  }
}

วิธีการโดยละเอียด อ่านตอนหน้าครับ เรื่อง Data Fetching สำหรับตอนนี้จะขอเป็นกึ่งๆ ทฤษฎี เพื่อให้เข้าใจ Concept ครับ

getServerSideProps

จะเป็น Server-side Rendering โดยตัว Next.js จะทำการ pre-render หน้า page ทุกๆ request ค่าที่ return ก็จะเป็น props ให้ Component นำไปใช้

export async function getServerSideProps(context) {
  return {
    props: {}, // will be passed to the page component as props
  }
}

ตัว getServerSideProps จะรันตอนไหนบ้าง?

  • ตอนที่เรา request หน้านั้นๆ (จะรันตอน request time ไม่ใช่ build time)
  • ตอนที่ request จาก client ผ่าน next/link ตัว Next.js จะส่ง request มาที่ server ซึ่งรัน getServerSideProps
  • getServerSideProps เราสามารถ export แค่เฉพาะ pages เท่านั้น ไม่สามารถใช้ที่ไฟล์อื่นๆ ได้

Client-side Rendering

นอกจาก Pre-render แบบ Static Generation และ Server-Side Rendering ก็ยังมี Client-Side Rendering อีก ในกรณีที่เราไม่ต้องการ pre-render ครับ

ตัวอย่างเคสนี้คือ เมื่อเวลา request หน้านี้ ตัว JavaScript จะถูกโหลดตอน (request time) เพื่อไป fetch ข้อมูล ถ้ามองง่ายๆ ก็เหมือนกับการที่เราเขียน React.js ปกติ และ fetch ข้อมูลด้วย useEffect() ครับ

function Profile() {
  const [data, setData] = useState(null)
  const [isLoading, setLoading] = useState(false)

  useEffect(() => {
    setLoading(true)
    fetch('/api/profile-data')
      .then((res) => res.json())
      .then((data) => {
        setData(data)
        setLoading(false)
      })
  }, [])

  if (isLoading) return <p>Loading...</p>
  if (!data) return <p>No profile data</p>

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.bio}</p>
    </div>
  )

🎉 จบแล้วครับ สำหรับตอนที่ 4 - ตอนนี้อาจจะเป็นคำอธิบายซะส่วนใหญ่ แล้วก็ยังไม่เห็นภาพเท่าไหร่ จนกว่าเราจะลองลงมือทำเอง รอตอนหน้านะครับ เรื่อง Data Fetching เราจะได้เห็น use case ต่างๆ และเข้าใจมากขึ้น

แบบฝึกหัด

  • ถ้าเราจะทำหน้า Dashboard เราควรใช้ Pre-render มั้ย และถ้าใช้ ควรใช้แบบไหน?
  • ถ้าเราไม่สนใจ SEO เราจำเป็นต้องใช้ Server-side rendering มั้ย
  • หน้าเว็บที่ข้อมูลอัพเดท realtime ตลอดเวลา ควรใช้ Pre-render แบบใด
  • เว็บข่าว หรือเว็บบล็อก ควรเลือกใช้แบบใด
Discord