- Next.js คืออะไร? + มาหัดเขียนเว็บด้วย Next.js กันดีกว่า
- ตอนที่ 1 - Hello Next.js เริ่มสร้างโปรเจ็ค
- ตอนที่ 2 - สร้าง Page และการ navigate ระหว่าง Pages
- ตอนที่ 3 - การจัดการ Assets, Metadata และ CSS
- ตอนที่ 4 - เรื่องของ Pre Rendering
- ตอนที่ 5 - Data Fetching และการดึงข้อมูลจาก API
- ตอนที่ 6 - การทำ Dynamic Routes
- ตอนที่ 7 - API Routes การทำ API ด้วย Next.js
ตอนที่ 4 - เรื่องของ Pre Rendering
เขียนวันที่ : Jun 19, 2022

สวัสดีครับ ตอนที่ 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

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

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 โดยใน functiongetStaticProps
เราสามารถ 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 แบบใด
- เว็บข่าว หรือเว็บบล็อก ควรเลือกใช้แบบใด