Astro Syntax Deep Dive
Expression: { } หย่อนเข้าไปใน JavaScript
หัวข้อที่มีชื่อว่า “Expression: { } หย่อนเข้าไปใน JavaScript”ที่ไหนก็ได้ใน template { } จะฝัง JavaScript expression แล้ว render ค่าที่ได้ออกมา ตัวแปรจาก frontmatter ใช้ได้เลย
---const name = "Ada";const count = 3;---<h1>Hello, {name}</h1><p>You have {count} messages.</p><p>Total: {count * 2}</p>ข้างใน { } ใส่ได้เฉพาะ expression เท่านั้น — อะไรที่ประเมินออกมาเป็นค่า ส่วน statement (บล็อก if, loop for) ต้องอยู่ใน frontmatter ใน template คุณเขียน control flow ในรูปของ expression ตามที่จะเห็นด้านล่าง
Conditional
หัวข้อที่มีชื่อว่า “Conditional”ใช้สำนวน logical-AND เพื่อ render บางอย่างเฉพาะตอนเงื่อนไขเป็นจริง และใช้ ternary เพื่อเลือกระหว่างสองทาง
---const isLoggedIn = true;const user = { name: "Ada", role: "admin" };---{isLoggedIn && <p>Welcome back, {user.name}</p>}
{user.role === "admin" ? <a href="/admin">Admin panel</a> : <a href="/account">Your account</a>}{cond && <div/>} จะ render element เมื่อ cond เป็น truthy และไม่ render อะไรเลยถ้าไม่ใช่ ส่วน ternary จะ render หนึ่งในสองทางเสมอ
ไม่มี directive สำหรับ loop โดยเฉพาะ — คุณ map array ให้เป็น markup เหมือน JSX เป๊ะ ๆ
---const posts = [ { id: 1, title: "First" }, { id: 2, title: "Second" },];---<ul> {posts.map((post) => <li>{post.title}</li>)}</ul>Astro ไม่ต้องใช้ prop key แบบที่ React ต้องใช้ — นี่คือ server rendering ไม่มี reconciliation แค่ map, return element, จบ
Fragment: จัดกลุ่มโดยไม่ต้องมี wrapper
หัวข้อที่มีชื่อว่า “Fragment: จัดกลุ่มโดยไม่ต้องมี wrapper”เวลาที่คุณต้อง return หลาย element โดยไม่อยากเพิ่ม DOM node ห่อ ให้ใช้ Fragment Astro รองรับทั้งแบบมีชื่อ <Fragment> และแบบย่อ <>
---const items = ["a", "b"];---<Fragment> <dt>Term</dt> <dd>Definition</dd></Fragment>
{items.map((x) => ( <> <span>{x}</span> <br /> </>))}Fragment ยังเป็นที่วาง directive set:* เวลาที่คุณไม่มี element ให้แปะด้วย (เดี๋ยวจะพูดถึง)
Render HTML ดิบ: set:html กับ set:text
หัวข้อที่มีชื่อว่า “Render HTML ดิบ: set:html กับ set:text”โดย default expression ที่ให้ค่าออกมาเป็น string จะถูก escape — Astro render เป็น text ดังนั้น <b>hi</b> จะโชว์ tag ออกมาตรง ๆ นั่นปลอดภัย เมื่อไหร่ที่คุณมี string HTML ที่เชื่อถือได้และอยากให้ render เป็น markup จริง ๆ (เช่น HTML จาก CMS ที่คุณคุมเอง) ให้ใช้ set:html
---const fromCms = "<strong>Bold from the CMS</strong>";const plain = "<not a tag>";---<div set:html={fromCms} /> <!-- renders as real bold markup --><div set:text={plain} /> <!-- renders the characters, escaped --><Fragment set:html={fromCms} /> <!-- no wrapper element -->set:html ข้าม escaping — ใช้กับ content ที่เชื่อถือได้เท่านั้น ไม่งั้นคุณเปิดช่องโหว่ XSS ส่วน set:text บังคับให้ค่าถูกมองเป็น plain text (คือ default ที่ปลอดภัยเขียนออกมาให้ชัด)
Spread attribute
หัวข้อที่มีชื่อว่า “Spread attribute”เมื่อคุณมี object ของ attribute ให้ spread ลงบน element ด้วย {...obj} — สะดวกเวลาส่ง props ต่อ
---const attrs = { id: "cta", class: "btn", "data-track": "signup" };---<a href="/join" {...attrs}>Join</a>Dynamic tag name
หัวข้อที่มีชื่อว่า “Dynamic tag name”คุณคำนวณได้ว่าจะ render element ตัวไหน กำหนดตัวแปรที่ขึ้นต้นด้วยตัวใหญ่ให้เป็นชื่อ tag แล้วเรียกใช้ตัวแปรนั้นได้เลย
---const level = 2;const Heading = `h${level}`; // "h2"---<Heading>Dynamic heading</Heading> <!-- renders <h2>Dynamic heading</h2> -->ตัวแปรต้อง ขึ้นต้นด้วยตัวใหญ่ เพื่อให้ Astro มองว่าเป็น reference ไปยัง component/tag ไม่ใช่ HTML tag ที่เขียนตรง ๆ
flowchart LR expr["expression in curly braces"] --> eval["evaluated on the server"] eval --> esc["string values are escaped by default"] esc --> html["safe HTML output"] eval --> raw["set:html bypasses escaping for trusted HTML"] raw --> html
ชื่อ attribute แบบ HTML ไม่ใช่แบบ JSX
หัวข้อที่มีชื่อว่า “ชื่อ attribute แบบ HTML ไม่ใช่แบบ JSX”จุดต่างที่ละเอียดแต่สำคัญจาก React: template ของ Astro ใช้ ชื่อ attribute แบบ HTML มาตรฐาน เป็น class ไม่ใช่ className; เป็น for ไม่ใช่ htmlFor คุณกำลังเขียน superset ของ HTML ดังนั้นชื่อแบบ HTML คือชื่อจริง