พลังของ v-for และ v-if: การจัดการเงื่อนไขและรายการข้อมูลอย่างโปร

1. 🎯 ตอนที่ 13: พลังของ v-for และ v-if สยบข้อมูลนับพันด้วยเงื่อนไขดั่งใจนึก
2. 📖 เปิดฉาก (The Hook)
น้องๆ ลองจินตนาการว่าเรากำลังทำระบบ E-commerce ที่มีสินค้าเป็นพันๆ ชิ้นดูสิครับ เราได้รับโจทย์ว่า “ให้ดึงสินค้าทั้งหมดมาแสดงผล แต่ถ้าสินค้าชิ้นไหนหมดสต๊อก ให้ซ่อนเอาไว้ และถ้าผู้ใช้ยังไม่ล็อกอิน ให้ขึ้นข้อความเตือน”
ถ้าเป็นยุคสมัยที่ต้องเขียน Vanilla JavaScript เราคงต้องเขียนลูป for สร้าง Element ยัดลงไปทีละบรรทัด พร้อมกับเขียนเงื่อนไข if ตรวจจับสถานะกันวุ่นวายจนโค้ดพันกันเป็นสปาเกตตีแน่นอน แต่ในอาณาจักร Vue.js เรามี “เวทมนตร์วิเศษ” ที่ชื่อว่า List Rendering (v-for) และ Conditional Rendering (v-if) ที่จะมาช่วยเสกให้ UI ของเราตอบสนองตามข้อมูลได้อย่างงดงาม
วันนี้พี่จะพาจิบกาแฟ และเจาะลึกวิธีการใช้งาน 2 คำสั่ง (Directives) นี้ พร้อมเปิดเผย “กฎเหล็กคลาสสิก” ที่นักพัฒนา Vue มือใหม่มักตกหลุมพรางจนแอปพังกระจาย มาดูกันครับว่ามือโปรเขาเขียนกันอย่างไร!
3. 🧠 แก่นวิชา (Core Concepts)
ก่อนอื่นเรามาแยกหน้าที่ของสองขุนพลนี้กันก่อนครับ:
🚦 Conditional Rendering: นักควบคุมเส้นทาง (v-if vs v-show)
เมื่อเราต้องการแสดงหรือซ่อนองค์ประกอบบนหน้าเว็บตามเงื่อนไข Vue มีให้เราเลือกใช้ 2 ท่าหลักๆ:
v-if,v-else-if,v-else(จอมทำลายล้างและสร้างใหม่): ทำงานเหมือนการเขียนif-elseทั่วไปเลยครับ จุดเด่นคือมันคือการ “แสดงผลแบบมีเงื่อนไขที่แท้จริง” (Real conditional rendering) หากเงื่อนไขเป็นเท็จ (False) Vue จะถอดชิ้นส่วนนั้นออกจาก DOM (Document Object Model) ไปเลย ราวกับมันไม่เคยมีอยู่บนโลกนี้v-show(ผ้าคลุมล่องหน): ต่างจากv-ifตรงที่v-showจะเรนเดอร์ชิ้นส่วนนั้นลงไปใน DOM เสมอ! แต่มันแค่ใช้ CSSdisplay: none;ในการซ่อนมันเอาไว้
💡 กฎการเลือกใช้ (Rule of Thumb):
- ใช้
v-showหากสิ่งนั้นต้องถูกสลับซ่อน/แสดงบ่อยๆ เพราะมันกินทรัพยากรน้อยกว่าเมื่อต้องเปลี่ยนสถานะ- ใช้
v-ifหากสิ่งนั้นนานๆ จะเปลี่ยนที หรือเราไม่ต้องการให้มันถูกเรนเดอร์เลยถ้าเงื่อนไขไม่ผ่านตั้งแต่แรก (Lazy evaluation)
🔁 List Rendering: เครื่องจักรโคลนนิ่ง (v-for)
v-for คือคำสั่งที่ใช้สร้างรายการ (List) ซ้ำๆ ตามข้อมูลที่เป็น Array หรือ Object โดยมีไวยากรณ์หลักคือ item in items (หรือจะใช้คำว่า of ก็ได้) นอกจากนี้เรายังสามารถดึงลำดับ (Index) ออกมาใช้งานได้ด้วยการเขียน (item, index) in items

4. 💻 ร่ายมนต์โค้ด (Show me the Code)
เรามาดูการรวมพลังของทั้ง 2 คำสั่งในการสร้างหน้ารายการสินค้ากันครับ:
<template>
<div class="store-container">
<h2>ร้านค้าเวทมนตร์ 🪄</h2>
<!-- ใช้ v-if เพื่อเช็คว่าโหลดข้อมูลเสร็จหรือยัง -->
<div v-if="isLoading" class="loading">กำลังโหลดสินค้า...</div>
<!-- หากมี Error ค่อยโชว์ v-else-if -->
<div v-else-if="hasError" class="error">เกิดข้อผิดพลาดในการโหลด!</div>
<!-- ถ้าทุกอย่างปกติ (v-else) ก็ลูปข้อมูลมาแสดง -->
<div v-else>
<ul>
<!-- ลูปข้อมูลด้วย v-for และกำหนด :key ให้แต่ละชิ้น -->
<li
v-for="(product, index) in activeProducts"
:key="product.id"
class="product-card"
>
<h3>{{ index + 1 }}. {{ product.name }}</h3>
<p>ราคา: {{ product.price }} บาท</p>
<!-- ใช้ v-show สำหรับปุ่มที่อาจจะถูกสลับไปมาบ่อยๆ -->
<button v-show="product.inStock">เพิ่มลงตะกร้า</button>
<span v-show="!product.inStock" class="out-of-stock">สินค้าหมด</span>
</li>
</ul>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const isLoading = ref(false)
const hasError = ref(false)
const products = ref([
{ id: 1, name: 'ดาบเอ็กซ์คาลิเบอร์', price: 5000, inStock: true, isActive: true },
{ id: 2, name: 'น้ำยาฟื้นพลัง', price: 150, inStock: false, isActive: true },
{ id: 3, name: 'ไม้กวาดหักๆ', price: 20, inStock: true, isActive: false } // สินค้านี้โดนระงับ
])
// 🌟 ตัวกรองสินค้า (ใช้ Computed แทนการเอา v-if ไปยัดใน v-for)
const activeProducts = computed(() => {
return products.value.filter(product => product.isActive)
})
</script>
<style scoped>
.out-of-stock { color: red; font-size: 0.8em; }
</style>5. 🛡️ เคล็ดลับจากคัมภีร์ลับ (Under the Hood / Pro-Tips)
ในโค้ดด้านบนมี “ความลับระดับ Senior” ซ่อนอยู่ 2 อย่างที่สำคัญมากๆ ครับ:
🚨 กฎเหล็กข้อที่ 1: ห้ามใช้ v-if และ v-for ในบรรทัด (Tag) เดียวกันเด็ดขาด!
นี่คือหลุมพรางที่โปรแกรมเมอร์ตกบ่อยที่สุด! บางคนอาจจะคิดแบบนี้: (❌ โค้ดที่ผิดและพัง)
<!-- หมายเหตุ: อย่าหาทำ! -->
<li v-for="user in users" v-if="user.isActive">
{{ user.name }}
</li>ทำไมถึงพัง? (The Technical Reason):
ในสถาปัตยกรรมของ Vue 3 v-if มีความสำคัญ (Precedence) สูงกว่า v-for ครับ!
นั่นหมายความว่า จังหวะที่ Vue กำลังจะตรวจสอบเงื่อนไข v-if="user.isActive" มันจะโวยวายทันทีว่า “เฮ้ย! ไม่รู้จักตัวแปร user!” เพราะการลูป v-for ยังไม่ทันได้เริ่มต้นสร้างตัวแปร user ให้มันเลย
✅ วิธีแก้ที่ถูกต้อง (The Right Way):
ให้ใช้ Computed Properties ในการกรอง (Filter) ข้อมูลเตรียมไว้ล่วงหน้า (เหมือนในโค้ดตัวอย่างข้อที่ 4 ที่เรากรอง activeProducts มารอไว้) แล้วค่อยนำ List ที่กรองแล้วมาลูปแสดงผล การทำแบบนี้ยังช่วยเรื่อง Performance ได้มาก เพราะไม่ต้องมารันการตรวจสอบเงื่อนไขทุกครั้งที่มีการ Re-render ครับ
🔑 กฎเหล็กข้อที่ 2: อย่าลืมใส่ :key เมื่อลูป v-for
น้องๆ สังเกตไหมว่าพี่ใส่ :key="product.id" ลงไปคู่กับ v-for เสมอ
เหตุผลก็คือ ภายใต้การทำงานของ Virtual DOM หากข้อมูลใน Array มีการเปลี่ยนแปลง (เช่น การเรียงลำดับใหม่ หรือการแทรกข้อมูลตรงกลาง) หากไม่มี :key Vue จะใช้วิธีเปลี่ยนข้อมูลดิบๆ ใน Element เดิม (In-place patch) ซึ่งอาจทำให้ UI เอ๋อได้ หาก List ของเรามีส่วนประกอบที่ต้องจำ State (เช่น ช่อง Input)
การใส่ :key ด้วยรหัส ID ที่ไม่ซ้ำกัน เป็นการไกด์บอก Vue ให้ติดตาม (Track) องค์ประกอบแต่ละชิ้นได้อย่างแม่นยำ ทำให้แอปของเราเสถียรและเร็วขึ้นมากครับ
6. 🏁 บทสรุป (To be continued…)
v-for และ v-if เป็นเครื่องมือพื้นฐานที่ทรงพลังมาก แต่ “พลังที่ยิ่งใหญ่มาพร้อมกับความรับผิดชอบที่ใหญ่ยิ่ง” การเข้าใจจังหวะการทำงานของมัน (Lifecycle) และลำดับความสำคัญ (Precedence) จะช่วยให้น้องๆ สามารถเขียนโค้ดที่รันได้อย่างรวดเร็วและไม่มีบั๊กรบกวนใจ
เมื่อเราควบคุมการแสดงผลของข้อมูลบนหน้าจอได้แล้ว ในบทถัดไป เราจะมาเรียนรู้วิธีการ “สกัดชิ้นส่วนหน้าจอ” ให้กลายเป็น Components ซึ่งถือเป็นหัวใจสูงสุดของสถาปัตยกรรม Frontend สมัยใหม่ เตรียมตัวรับมือกับการส่งผ่านข้อมูลระหว่างพ่อกับลูก (Props & Emits) กันได้เลยครับ!
ต้องการที่ปรึกษาและพัฒนาระบบ Web Application หรือ Frontend Architecture ให้กับธุรกิจของคุณ? ทีมงาน WP Solution พร้อมให้บริการออกแบบและพัฒนาซอฟต์แวร์แบบครบวงจร ดูรายละเอียดบริการของเราได้ที่: www.wpsolution2017.com หรือพูดคุยปรึกษาเบื้องต้นได้ที่ Line: wisit.p