<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: c_nooknook_daily_prompt</title>
    <description>The latest articles on DEV Community by c_nooknook_daily_prompt (@nooknookwork).</description>
    <link>https://dev.to/nooknookwork</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1894783%2Ffec2d215-0cc2-4354-9ed7-88cd62be37f3.jpeg</url>
      <title>DEV Community: c_nooknook_daily_prompt</title>
      <link>https://dev.to/nooknookwork</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nooknookwork"/>
    <language>en</language>
    <item>
      <title>ประเภทของงาน (Type of Work) หรือเรียกได้ว่าเป็น หมวดหมู่ของงานในสาย Software Development</title>
      <dc:creator>c_nooknook_daily_prompt</dc:creator>
      <pubDate>Thu, 24 Jul 2025 03:40:37 +0000</pubDate>
      <link>https://dev.to/nooknookwork/praephthkhngngaan-type-of-work-hruueeriiykaidwaaepn-hmwdhmuukhngngaanainsaay-software-development-469k</link>
      <guid>https://dev.to/nooknookwork/praephthkhngngaan-type-of-work-hruueeriiykaidwaaepn-hmwdhmuukhngngaanainsaay-software-development-469k</guid>
      <description>&lt;p&gt;งานประเภท Code Review, Database Optimization จัดอยู่ในหมวดหมู่ "Technical Tasks" หรือ "Engineering Work Categories" ซึ่งสามารถแบ่งได้หลายประเภทขึ้นอยู่กับองค์กร แต่โดยทั่วไปสากลนิยมใช้ประเภทหลัก ๆ ดังนี้:&lt;/p&gt;

&lt;p&gt;🔧 ประเภทของงานด้าน Software Development (สากลนิยม)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;หมวดหมู่&lt;/th&gt;
&lt;th&gt;ตัวอย่างงาน&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1. Feature Development&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;เพิ่มฟีเจอร์ใหม่, เขียน API, เพิ่มหน้าจอใหม่&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2. Bug Fixing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;แก้ไขบั๊กจาก QA หรือ production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;3. Code Review&lt;/strong&gt; ✅&lt;/td&gt;
&lt;td&gt;ตรวจสอบและให้ feedback โค้ดเพื่อนร่วมทีม&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4. Refactoring&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ปรับปรุงโค้ดเดิมให้ดีขึ้นโดยไม่เปลี่ยนพฤติกรรม&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;5. Performance Optimization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;เช่น ✅ &lt;code&gt;Database Optimization&lt;/code&gt;, ลด response time, memory leak&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;6. DevOps / Infra&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CI/CD, Docker, Kubernetes, monitoring tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;7. Testing / QA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;เขียน unit test, integration test, manual test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;8. Documentation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;API docs, README, internal dev guide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;9. Research / Spike&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ทดลองเทคโนโลยีใหม่, proof of concept (POC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;10. Support / Maintenance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;แก้ปัญหาเร่งด่วน, deploy hotfix&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;💡 หมายเหตุเพิ่มเติม:&lt;br&gt;
ถ้าใช้ Jira หรือ Asana, องค์กรมักจะตั้งประเภทงานแบบนี้ไว้ใน field เช่น "Task Type", "Issue Type" หรือ "Work Category"&lt;/p&gt;

&lt;p&gt;บางองค์กรอาจรวม Code Review เป็นส่วนหนึ่งของกระบวนการ QA หรือ Dev Process&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>React Native CLI vs Expo: เลือกอะไรดีสำหรับการพัฒนาแอปของคุณ?</title>
      <dc:creator>c_nooknook_daily_prompt</dc:creator>
      <pubDate>Thu, 17 Jul 2025 10:14:17 +0000</pubDate>
      <link>https://dev.to/nooknookwork/react-native-cli-vs-expo-eluuekaairdiisamhrabkaarphathnaaaepkhngkhun-1l7d</link>
      <guid>https://dev.to/nooknookwork/react-native-cli-vs-expo-eluuekaairdiisamhrabkaarphathnaaaepkhngkhun-1l7d</guid>
      <description>&lt;p&gt;🎯 &lt;strong&gt;คำแนะนำสั้น ๆ&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;Expo: เหมาะกับผู้เริ่มต้น, MVP, ทีมเล็ก, ต้องการเร็ว&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;React Native CLI: เหมาะกับทีม dev จริงจัง, ใช้ native module เยอะ, ต้องการควบคุมทุกอย่างเอง&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;React Native เป็นหนึ่งในเฟรมเวิร์กยอดนิยมสำหรับการพัฒนาแอปมือถือแบบ cross-platform แต่เมื่อคุณเริ่มต้น คุณจะพบว่า React Native มี 2 ทางให้เลือกคือ “React Native CLI” และ “Expo”&lt;/p&gt;

&lt;p&gt;บทความนี้จะพาคุณมารู้จักความแตกต่าง ข้อดี ข้อเสีย และเคล็ดลับในการเลือกเครื่องมือที่เหมาะสมกับโปรเจกต์ของคุณ&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React Native CLI&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เป็นเครื่องมือพื้นฐานของ React Native&lt;/li&gt;
&lt;li&gt;ต้องติดตั้ง Xcode (iOS) และ Android Studio (Android)&lt;/li&gt;
&lt;li&gt;มีความยืดหยุ่นสูง&lt;/li&gt;
&lt;li&gt;ไม่สามารถรันบนเว็บเบราเซอร์ได้โดยตรงถ้ารันต้องใช้ Map react-native ไปยัง react-native-web ปรับ Babel ให้รองรับ React Native&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Expo&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เป็น framework + platform ที่ช่วยให้พัฒนาแอปได้ง่ายขึ้น&lt;/li&gt;
&lt;li&gt;มี Expo Go ให้ทดลองแอปบนมือถือได้ทันที&lt;/li&gt;
&lt;li&gt;เหมาะกับคนที่อยากเริ่มเร็ว ไม่อยาก config เยอะ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Expo Go คืออะไร?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expo Go คือแอปสำเร็จรูป (มีใน App Store และ Google Play) ที่สามารถโหลดโปรเจกต์ Expo ของคุณมารันแบบ real-time ได้ ผ่าน QR Code&lt;/li&gt;
&lt;li&gt;Expo Go คือแอปมือถือที่ช่วยให้นักพัฒนาสามารถ “รัน” และ “ทดสอบ” แอปที่เขียนด้วย Expo (React Native) ได้ทันที โดย ไม่ต้อง build แอปเป็น .apk หรือ .ipa&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ไฟล์ .apk และ .ipa คืออะไร?&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ประเภทไฟล์&lt;/th&gt;
&lt;th&gt;แพลตฟอร์ม&lt;/th&gt;
&lt;th&gt;คืออะไร&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.apk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Android&lt;/td&gt;
&lt;td&gt;ย่อมาจาก &lt;strong&gt;Android Package&lt;/strong&gt; เป็นไฟล์ติดตั้งแอป Android&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.ipa&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;iOS&lt;/td&gt;
&lt;td&gt;ย่อมาจาก &lt;strong&gt;iOS App Store Package&lt;/strong&gt; เป็นไฟล์ติดตั้งแอปบน iPhone / iPad&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;⚙️ &lt;strong&gt;การเริ่มต้นใช้งาน&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React Native CLI&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx react-native init MyApp
cd MyApp
npx react-native run-ios / run-android

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expo&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-expo-app MyApp
cd MyApp
npx expo start

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ ข้อดี-ข้อเสีย&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;หัวข้อ&lt;/th&gt;
&lt;th&gt;React Native CLI&lt;/th&gt;
&lt;th&gt;Expo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;การติดตั้ง&lt;/td&gt;
&lt;td&gt;ต้อง config เยอะ&lt;/td&gt;
&lt;td&gt;ใช้งานง่ายมาก&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native Modules&lt;/td&gt;
&lt;td&gt;เขียน Native Code ได้เต็มที่&lt;/td&gt;
&lt;td&gt;จำกัด ต้อง Eject ถึงจะเขียน Native ได้&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debug/Test&lt;/td&gt;
&lt;td&gt;ต้องใช้ emulator/simulator&lt;/td&gt;
&lt;td&gt;ใช้แอป Expo Go ได้เลย&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build&lt;/td&gt;
&lt;td&gt;ต้องตั้งค่าทุกอย่างเอง&lt;/td&gt;
&lt;td&gt;Expo มี Cloud Build (ง่าย)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ขนาดแอป&lt;/td&gt;
&lt;td&gt;เล็กกว่า&lt;/td&gt;
&lt;td&gt;ใหญ่กว่าเพราะ include lib มาตรฐาน&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เรียนรู้&lt;/td&gt;
&lt;td&gt;ยากกว่าเล็กน้อย&lt;/td&gt;
&lt;td&gt;เป็นมิตรกับผู้เริ่มต้น&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🧠 แล้วควรเลือกอะไร?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;คุณคือ...&lt;/th&gt;
&lt;th&gt;ควรเลือก&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;มือใหม่ อยากเริ่มเร็ว&lt;/td&gt;
&lt;td&gt;✅ Expo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ต้องใช้ Native SDK พิเศษ&lt;/td&gt;
&lt;td&gt;✅ React Native CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;โปรเจกต์เล็ก-กลาง&lt;/td&gt;
&lt;td&gt;✅ Expo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;โปรเจกต์องค์กร/ซับซ้อน&lt;/td&gt;
&lt;td&gt;✅ React Native CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;💡 ตัวอย่างสถานการณ์จริง&lt;/p&gt;

&lt;p&gt;“ฉันอยากทำแอป To-do List + กล้องถ่ายรูป”&lt;br&gt;
ถ้าใช้ Expo อาจเจอข้อจำกัดเรื่องการเข้าถึง native camera library บางตัว — แก้โดย eject&lt;/p&gt;

&lt;p&gt;“ฉันต้องใช้ SDK ธนาคาร”&lt;br&gt;
ใช้ React Native CLI ดีกว่า เพราะคุณสามารถ integrate native module ได้เต็มที่&lt;/p&gt;

&lt;p&gt;🔚 สรุป&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React Native CLI เหมาะกับนักพัฒนาที่ต้องการควบคุมระบบได้เต็มที่
&lt;/li&gt;
&lt;li&gt;Expo เหมาะกับผู้เริ่มต้นและโปรเจกต์ที่อยากพัฒนาเร็วโดยไม่ต้องจัดการ native มากนัก&lt;/li&gt;
&lt;li&gt;ไม่มีทางเลือกไหนดีที่สุด แต่มี “ทางเลือกที่เหมาะที่สุดสำหรับคุณ”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📌 ความแตกต่างระหว่าง React Native CLI vs Expo&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;หัวข้อ&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;React Native CLI&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Expo&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;⚙️ &lt;strong&gt;การติดตั้งและเริ่มต้น&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ต้องติดตั้ง Xcode, Android Studio, และตั้งค่า environment&lt;/td&gt;
&lt;td&gt;ใช้งานง่าย ติดตั้งเร็ว ไม่ต้อง setup Android/iOS SDK เอง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔌 &lt;strong&gt;การใช้ Native Modules&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;เขียน/ใช้ native code ได้เต็มที่ (เช่น Java, Swift, Objective-C)&lt;/td&gt;
&lt;td&gt;จำกัดเฉพาะ module ที่ Expo รองรับ เว้นแต่จะ “eject”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📱 &lt;strong&gt;การทดสอบแอป&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ใช้ emulator หรือ device จริง&lt;/td&gt;
&lt;td&gt;ใช้แอป &lt;strong&gt;Expo Go&lt;/strong&gt; สแกน QR ก็ preview ได้ทันที&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🛠️ &lt;strong&gt;ความยืดหยุ่น&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ยืดหยุ่นสูง ปรับแต่งได้ทุกส่วน&lt;/td&gt;
&lt;td&gt;สะดวกแต่มีข้อจำกัดในการเข้าถึง native functionality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧱 &lt;strong&gt;ขนาดแอป (APK/IPA)&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;เบากว่า เพราะ build เฉพาะ module ที่ใช้&lt;/td&gt;
&lt;td&gt;ใหญ่กว่าเพราะรวม libraries ที่อาจไม่ได้ใช้ทั้งหมด&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔧 &lt;strong&gt;การ build และ release&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ต้อง setup build ด้วยตนเอง (Xcode, Gradle)&lt;/td&gt;
&lt;td&gt;มี Expo CLI + EAS Build (cloud build ง่ายๆ)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📦 &lt;strong&gt;Dependency และ Third-party&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ใช้ package ได้เกือบทั้งหมด&lt;/td&gt;
&lt;td&gt;ใช้ได้เฉพาะ package ที่รองรับกับ Expo หรือ custom หลัง eject&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧪 &lt;strong&gt;การ debug และ devtools&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ใช้ Metro bundler, React DevTools, Flipper ฯลฯ&lt;/td&gt;
&lt;td&gt;รองรับ debug ผ่าน Expo DevTools, web UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;💼 &lt;strong&gt;เหมาะกับโปรเจกต์แบบไหน&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;โปรเจกต์ที่ซับซ้อน, ต้องใช้ native SDK, มีทีม dev&lt;/td&gt;
&lt;td&gt;MVP, โปรเจกต์เล็ก-กลาง, แอป internal, นักพัฒนาเดี่ยว&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔃 &lt;strong&gt;การ Eject&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ไม่จำเป็น (เพราะควบคุมทุกอย่างอยู่แล้ว)&lt;/td&gt;
&lt;td&gt;หากต้องใช้ native module ต้อง eject จาก Expo ไปยัง CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🟥 สิ่งที่ React Native CLI ทำได้ แต่ Expo ทำไม่ได้ (หรือจำกัด)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ฟีเจอร์&lt;/th&gt;
&lt;th&gt;คำอธิบาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🧩 &lt;strong&gt;ใช้งาน Native Modules ที่ไม่มีใน Expo ได้&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;เช่น SDK ธนาคาร, Bluetooth library, ARKit, เครื่องสแกนลายนิ้วมือแบบเฉพาะ ฯลฯ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🛠️ &lt;strong&gt;เขียน native code ได้เต็มรูปแบบ&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;แก้ไขไฟล์ &lt;code&gt;.java&lt;/code&gt;, &lt;code&gt;.kt&lt;/code&gt;, &lt;code&gt;.swift&lt;/code&gt;, &lt;code&gt;.objc&lt;/code&gt; ได้โดยตรง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📦 &lt;strong&gt;ติดตั้งทุก 3rd-party libraries ได้&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;รวมถึง library ที่ต้อง link native code ด้วย&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🚀 &lt;strong&gt;แอปมีขนาดเล็กกว่า (ถ้า optimize)&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ไม่มีการรวม library ที่ไม่ใช้เข้าไปโดยอัตโนมัติ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📂 &lt;strong&gt;ควบคุม build tools ได้ทั้งหมด&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ปรับแต่ง Gradle, Xcode, keystore ฯลฯ ได้ละเอียด&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📍 &lt;strong&gt;ใช้เครื่องมือ CI/CD เฉพาะทางได้ง่ายกว่า&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;เช่น Fastlane, Bitrise, Github Actions แบบ native-level&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🟩 สิ่งที่ Expo ทำได้ แต่ React Native CLI ทำไม่ได้ (หรือทำยาก)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ฟีเจอร์&lt;/th&gt;
&lt;th&gt;คำอธิบาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;⚡ &lt;strong&gt;เริ่มต้นได้เร็วมาก&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Expo มี &lt;code&gt;create-expo-app&lt;/code&gt; พร้อม DevTools GUI, ไม่ต้อง config environment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📱 &lt;strong&gt;Preview แอปทันทีผ่าน QR Code&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ใช้แอป &lt;strong&gt;Expo Go&lt;/strong&gt; บนมือถือ สแกน QR code ก็ทดสอบแอปได้เลย&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;☁️ &lt;strong&gt;Cloud Build (EAS Build)&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;สร้างไฟล์ .apk / .ipa บน Cloud ได้โดยไม่ต้องลง Xcode หรือ Android Studio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔄 &lt;strong&gt;Hot Reload/Live Reload เสถียรกว่า&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Expo Go ให้ประสบการณ์ reload ที่รวดเร็วมากบนอุปกรณ์จริง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔌 &lt;strong&gt;ใช้งาน Native APIs ได้เลยโดยไม่ต้องติดตั้งเพิ่ม&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;เช่นกล้อง, location, notification, sensors ผ่าน &lt;code&gt;expo-modules&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧪 &lt;strong&gt;Testing บน Web ได้ (expo web)&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;พัฒนาแอปบนเว็บก่อน deploy mobile ด้วย Expo for Web&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🎯 &lt;strong&gt;Managed Workflow&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ไม่ต้องแตะ native code เลย ตลอด lifecycle การพัฒนา&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🎁 &lt;strong&gt;Expo Snack (ออนไลน์ IDE)&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;เขียน React Native บนเว็บและ preview ได้ทันที ไม่ต้องติดตั้งอะไรเลย&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🎯 สรุปแบบเข้าใจง่าย&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Expo&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;React Native CLI&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🚀 เริ่มเร็ว&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔌 เขียน native code เอง&lt;/td&gt;
&lt;td&gt;❌ (ต้อง eject)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧪 รองรับ native SDK พิเศษ&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;☁️ Cloud Build ง่าย&lt;/td&gt;
&lt;td&gt;✅ (EAS Build)&lt;/td&gt;
&lt;td&gt;❌ (ต้อง config เอง)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📱 ใช้ Expo Go preview&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🎯 ควบคุมละเอียดทุกส่วน&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🔄 ถ้าใช้ Expo แล้วอยากได้พลัง CLI ทำไง?&lt;br&gt;
Expo รองรับการ Eject (Convert ไปใช้ CLI) ได้ครับ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx expo eject

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หลัง eject แล้วคุณจะได้ native Android/iOS project ซึ่งสามารถติดตั้ง native module และปรับแต่งได้เหมือน React Native CLI ปกติ&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>React Native Beginner</title>
      <dc:creator>c_nooknook_daily_prompt</dc:creator>
      <pubDate>Thu, 17 Jul 2025 09:22:40 +0000</pubDate>
      <link>https://dev.to/nooknookwork/react-native-beginner-33im</link>
      <guid>https://dev.to/nooknookwork/react-native-beginner-33im</guid>
      <description>&lt;p&gt;&lt;strong&gt;React Native Beginner&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;เป้าหมาย:&lt;/strong&gt;&lt;br&gt;
เตรียม macOS ให้พร้อมสำหรับการสร้างแอป React Native (แบบ Native – Android และ iOS)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.เตรียมเครื่องก่อนติดตั้ง&lt;/strong&gt;&lt;br&gt;
สเปกเครื่องที่แนะนำ&lt;br&gt;
OS: macOS Ventura หรือใหม่กว่า&lt;/p&gt;

&lt;p&gt;RAM: อย่างน้อย 8 GB (แนะนำ 16 GB ขึ้นไปเพื่อรัน Android Emulator + iOS Simulator พร้อมกัน)&lt;/p&gt;

&lt;p&gt;พื้นที่ว่างในเครื่อง: 15 GB ขึ้นไป&lt;br&gt;
(Android SDK, Xcode, Gradle, Node Modules กินพื้นที่มาก)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.ติดตั้งเครื่องมือพื้นฐาน&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Homebrew (ตัวช่วยติดตั้งเครื่องมือ)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;https://brew.sh/&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Node.js (แนะนำใช้ nvm หรือ volta)
ติดตั้ง Node.js และแนะนำเวอร์ชัน (เช่น node &amp;gt;= 18)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install volta /or
volta install node

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตรวจสอบการติดตั้ง node&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;ติดตั้ง NPM
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node install npm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตรวจสอบการติดตั้ง npm&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;ติดตั้ง Watchman (สำหรับ macOS ใช้ตรวจจับไฟล์เปลี่ยน)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install watchman
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตรวจสอบการติดตั้ง&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;watchman -v  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;ติดตั้ง cocaopods
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install cocoapods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;ติดตั้ง JDK (Java Development Kit)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install temurin17
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตรวจสอบการติดตั้ง Java&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;java -version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.ติดตั้ง xcode and simulator (iPhone 16 pro and iOS 18.5)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apps.apple.com/us/app/xcode/id497799835?mt=12/" rel="noopener noreferrer"&gt;https://apps.apple.com/us/app/xcode/id497799835?mt=12/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6q6v7sthkt32ooaq981.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6q6v7sthkt32ooaq981.png" alt=" " width="800" height="1708"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.ติดตั้ง andriod studio&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/studio?authuser=6&amp;amp;hl=th" rel="noopener noreferrer"&gt;https://developer.android.com/studio?authuser=6&amp;amp;hl=th&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ตั้งค่าดังนี้&lt;/p&gt;

&lt;p&gt;4.1.ไปที่ sidebar Tools -&amp;gt; SDK manager&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fde9amt7lhfcjtf5qd24r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fde9amt7lhfcjtf5qd24r.png" alt=" " width="418" height="752"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4.2.Android SDK Build-Tools Version 35.0.0&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F46dz2pcny3swvy2qlzm9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F46dz2pcny3swvy2qlzm9.png" alt=" " width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4.3.ติดตั้ง NDK (side by side) 27.1.12297006&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frgeglukfn53d3chpz9f0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frgeglukfn53d3chpz9f0.png" alt=" " width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4.4.ติดตั้ง Andriod SDK-Command-line Tools (lastest)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdo5qct26gt17khe0qnw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdo5qct26gt17khe0qnw.png" alt=" " width="800" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4.5.CMake 3.22.1&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzr6tclrwqrqrzr6udtl3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzr6tclrwqrqrzr6udtl3.png" alt=" " width="800" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4.6.Andriod Emulator, Andriod SDK Platform Tools&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjw48d50ew5nrjg7t6ytn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjw48d50ew5nrjg7t6ytn.png" alt=" " width="800" height="70"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;in /.zshrc file
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$ANDROID_HOME/emulator:$ANDROID_HOME/platform-tools:$ANDROID_HOME/b$

export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/your-version
export PATH=$ANDROID_NDK_HOME:$PATH

export PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"
export CPPFLAGS="-I/opt/homebrew/opt/openjdk@17/include"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.สร้าง project in VScode&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx @react-native-community/cli init MyReactNativeFirst

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;answer Y เพื่อ install pod&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;สร้าง file local.properties in andriod folder&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cmake.dir=/Users/your-user-name/Library/Android/sdk/cmake/3.22.1
ndk.dir=/Users/your-user-name/Library/Android/sdk/ndk/27.1.12297006
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;on MacOS สำหรับกำหนดค่า memory ในเครื่อง และภาษาเพื่อให้เสถียร
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#Specifies the JVM arguments used for the daemon process.
#The setting is particularly useful for tweaking memory settings.
#Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
org.gradle.jvmargs=-Xmx2048m -Duser.country=US -Duser.language=en -XX:MaxMetaspaceSize=512m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 แล้วทำไมมักเห็นใน org.gradle.jvmargs?&lt;br&gt;
เพราะบางครั้ง Gradle หรือ plugin บางตัวอาจจะแสดงผลลัพธ์แตกต่างกันไปตาม locale ของเครื่อง&lt;br&gt;
เช่น:&lt;br&gt;
เครื่อง dev เป็นภาษาไทย → build log หรือ error message ออกมาเป็นภาษาไทย&lt;br&gt;
เวลาเขียน shell script หรือเขียน plugin แล้วเอาไปใช้บน server (ที่ใช้ locale อังกฤษ) → อาจเจอพฤติกรรมต่างกัน&lt;br&gt;
🎯 ดังนั้นจึงตั้ง -Duser.country=US -Duser.language=en เพื่อให้ผลลัพธ์ทุกคนเหมือนกัน (ใช้ US/English เสมอ)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.run project&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd MyReactNativeFirst
|
v
npm install

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;ถ้ามี error
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx react-native doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;ถ้าอยากดู รายละเอียด
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx react-native info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7.รัน android&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;react-native run-android
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8.รัน ios&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;react-native run-ios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>programming</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>ใช้ git flow กันเถอะ</title>
      <dc:creator>c_nooknook_daily_prompt</dc:creator>
      <pubDate>Mon, 07 Jul 2025 23:04:06 +0000</pubDate>
      <link>https://dev.to/nooknookwork/aich-git-flow-kanetha-58c2</link>
      <guid>https://dev.to/nooknookwork/aich-git-flow-kanetha-58c2</guid>
      <description>&lt;p&gt;&lt;strong&gt;แนวคิดของ Git Flow&lt;/strong&gt;&lt;br&gt;
Git Flow คือรูปแบบการจัดการ branch ที่เหมาะกับการพัฒนา software เป็นเวอร์ชันๆ โดยมี branch หลักๆ ดังนี้:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Branch&lt;/th&gt;
&lt;th&gt;ใช้ทำอะไร&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;main&lt;/code&gt; หรือ &lt;code&gt;master&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;เก็บ code ที่พร้อมขึ้น production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;develop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;เก็บ code ที่อยู่ระหว่างการพัฒนา (เตรียม release)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;feature/*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;พัฒนา feature ใหม่&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;release/*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;เตรียม code สำหรับการ release&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hotfix/*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;แก้ไข bug ด่วนจาก production&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;ขั้นตอนเริ่มใช้ Git Flow อย่างถูกต้อง&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ติดตั้ง Git Flow (ครั้งเดียว)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Mac (ผ่าน Homebrew)
brew install git-flow

# Ubuntu/Debian
sudo apt install git-flow

# Windows: ใช้ Git Bash แล้วติดตั้งผ่าน Git Extension หรือ Chocolatey
choco install git-flow-avh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ตอนเริ่มต้น: เตรียม branch&lt;/strong&gt;&lt;br&gt;
Checkout develop และดึงโค้ดล่าสุด&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout develop
git pull origin develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📍 ทำบน: develop&lt;br&gt;
📌 เพื่อให้แน่ใจว่า feature ใหม่ของคุณเริ่มจาก develop เวอร์ชันล่าสุด&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;สร้าง feature branch ด้วย Git Flow&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;เริ่มต้นใช้งานในโปรเจกต์&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ไปยังโฟลเดอร์โปรเจกต์ แล้วพิมพ์:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git flow init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ระบบจะถามคุณว่าชื่อ branch ต่างๆ จะใช้ชื่ออะไร เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Branch สำหรับ production: main&lt;/li&gt;
&lt;li&gt;Branch สำหรับ development: develop&lt;/li&gt;
&lt;li&gt;Prefix สำหรับ feature branch: feature/&lt;/li&gt;
&lt;li&gt;Prefix สำหรับ release branch: release/&lt;/li&gt;
&lt;li&gt;Prefix สำหรับ hotfix branch: hotfix/&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📌 กด Enter ใช้ค่า default ได้เลย เว้นแต่ทีมคุณมีการตั้งชื่อเฉพาะ&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;สร้าง feature branch ด้วย Git Flow&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git flow feature start branch-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📍 ทำบน: develop → feature/branch-name (Git Flow จะสลับให้อัตโนมัติ)&lt;br&gt;
📌 สร้าง branch feature/branch-name จาก develop&lt;/p&gt;

&lt;p&gt;สมมติว่าทำ login-page&lt;br&gt;
&lt;strong&gt;ตอนพัฒนา: เขียนโค้ดและ commit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ทำงานบน feature/branch-name&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add .
git commit -m "feat(login page): สร้างหน้า login"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📍 ทำบน: feature/login-page&lt;br&gt;
📌 เพิ่มไฟล์และ commit งานตามปกติ&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Push ขึ้น remote เพื่อ backup / ร่วมงาน&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -u origin feature/login-page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📍 ทำบน: feature/login-page&lt;br&gt;
📌 ดัน branch นี้ขึ้น remote เพื่อให้คนอื่นเห็นหรือทำ PR ได้&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ตอนจะ finish หรือ merge กลับ develop&lt;/strong&gt;&lt;br&gt;
ดึง develop ล่าสุดมารวมก่อน (ป้องกัน conflict ภายหลัง)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout develop
git pull origin develop    # ดึง develop ล่าสุด
git checkout feature/login-page
git rebase develop         # รวม develop เข้ามาใน feature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📍 ทำบน: feature/login-page&lt;br&gt;
📌 เพื่อให้แน่ใจว่า feature ของคุณ up-to-date กับ develop และดู conflict ตั้งแต่ตอนนี้&lt;/p&gt;

&lt;p&gt;❗ ถ้ามี conflict ตอน git rebase develop&lt;br&gt;
แก้ไฟล์ที่ conflict ด้วย editor&lt;/p&gt;

&lt;p&gt;เมื่อแก้เสร็จ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add .
git rebase --continue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(ทำซ้ำถ้ามี conflict หลายจุด)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Push หลังจาก rebase แล้ว (ต้องใช้ --force หรือ --force-with-lease)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push --force-with-lease
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📍 ทำบน: feature/login-page&lt;br&gt;
📌 เพราะ rebase จะเปลี่ยนประวัติ commit ต้อง force push ขึ้น remote&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ตอนจบ: merge feature กลับ develop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finish ด้วย Git Flow (หลัง rebase และ push เสร็จแล้ว)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git flow feature finish login-page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📍 ทำบน: feature/login-page&lt;br&gt;
📌 จะ merge เข้ากับ develop และลบ feature branch&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Push develop ขึ้น remote&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push origin develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📍 ทำบน: develop&lt;br&gt;
📌 ดันโค้ดล่าสุดขึ้น remote&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;สรุป Workflow ทั้งหมด&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# เริ่ม
git checkout develop
git pull origin develop
git flow feature start login-page

# ทำงาน
# --&amp;gt; เขียนโค้ด --&amp;gt;
git add .
git commit -m "feat: หน้า login"
git push -u origin feature/login-page

# ก่อน merge กลับ
git checkout develop
git pull origin develop
git checkout feature/login-page
git rebase develop         # รวม develop ล่าสุด

# ถ้า conflict: แก้ + commit
git add .
git rebase --continue

# หลัง rebase
git push --force-with-lease

# Finish
git flow feature finish login-page
git push origin develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;อธิบายคำสั่งสำคัญ&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;คำสั่ง&lt;/th&gt;
&lt;th&gt;ใช้ทำอะไร&lt;/th&gt;
&lt;th&gt;ใช้ตอนอยู่ที่ branch&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git flow feature start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;สร้าง branch feature&lt;/td&gt;
&lt;td&gt;develop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git add .&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;เพิ่มไฟล์ทั้งหมดเข้าสู่ staging&lt;/td&gt;
&lt;td&gt;feature/*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git commit -m&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;commit งาน&lt;/td&gt;
&lt;td&gt;feature/*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git push -u origin feature/*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ดัน branch feature ไป remote&lt;/td&gt;
&lt;td&gt;feature/*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git pull origin develop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ดึง develop ล่าสุด&lt;/td&gt;
&lt;td&gt;develop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git rebase develop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;รวม develop เข้ามาใน feature (clean history)&lt;/td&gt;
&lt;td&gt;feature/*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git rebase --continue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ดำเนินการ rebase หลังแก้ conflict&lt;/td&gt;
&lt;td&gt;feature/*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git push --force-with-lease&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;push หลัง rebase (force แบบปลอดภัย)&lt;/td&gt;
&lt;td&gt;feature/*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git flow feature finish&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;merge เข้า develop + ลบ branch&lt;/td&gt;
&lt;td&gt;feature/*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git push origin develop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;push develop ที่ merge แล้ว&lt;/td&gt;
&lt;td&gt;develop&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;สรุป Git Flow Feature Branch พร้อม branch ปัจจุบัน&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ขั้นตอน&lt;/th&gt;
&lt;th&gt;คำสั่ง&lt;/th&gt;
&lt;th&gt;อยู่ที่ branch&lt;/th&gt;
&lt;th&gt;อธิบาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. เริ่ม feature ใหม่&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git checkout develop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;develop&lt;/td&gt;
&lt;td&gt;เตรียมตัวก่อนเริ่ม feature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git flow feature start ชื่อ&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;develop → feature/ชื่อ-feature&lt;/td&gt;
&lt;td&gt;สร้างและสลับไป branch feature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. ทำงานแก้โค้ด&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git add .&lt;/code&gt; + &lt;code&gt;git commit&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;feature/ชื่อ-feature&lt;/td&gt;
&lt;td&gt;commit โค้ดใน feature branch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. (ถ้ามี) push ขึ้น remote&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git push -u origin feature/ชื่อ&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;feature/ชื่อ-feature&lt;/td&gt;
&lt;td&gt;ส่ง branch feature ขึ้น remote&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. จบ feature และ merge กลับ&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git flow feature finish ชื่อ&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;feature/ชื่อ-feature → develop&lt;/td&gt;
&lt;td&gt;merge เข้า develop, ลบ feature, สลับไป develop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. push develop กลับ remote&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git push origin develop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;develop&lt;/td&gt;
&lt;td&gt;ส่ง develop branch ล่าสุดขึ้น remote&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>git</category>
    </item>
    <item>
      <title>Angular for beginner</title>
      <dc:creator>c_nooknook_daily_prompt</dc:creator>
      <pubDate>Tue, 01 Jul 2025 06:08:57 +0000</pubDate>
      <link>https://dev.to/nooknookwork/angular-for-beginner-i1m</link>
      <guid>https://dev.to/nooknookwork/angular-for-beginner-i1m</guid>
      <description>&lt;p&gt;โครงสร้างโปรเจกต์ Angular ที่เป็น มาตรฐานและสามารถขยายได้ในระยะยาว ซึ่งเหมาะกับโปรเจกต์ที่มี components, routes, services, types, และ pages&lt;/p&gt;

&lt;p&gt;🏗️ โครงสร้างโปรเจกต์ Angular (แนะนำ)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── app/
│   ├── core/                      # ส่วนกลางที่ใช้ทั่วทั้งแอป (singleton services, guards, interceptors)
│   │   ├── services/
│   │   ├── guards/
│   │   ├── interceptors/
│   │   └── core.module.ts
│
│   ├── shared/                    # ส่วนที่แชร์ได้ทุกหน้า (components, pipes, directives, models)
│   │   ├── components/
│   │   ├── pipes/
│   │   ├── directives/
│   │   ├── models/               # types/interfaces ที่แชร์ได้
│   │   └── shared.module.ts
│
│   ├── pages/                     # แต่ละหน้า เช่น Home, Login, Dashboard ฯลฯ
│   │   ├── home/
│   │   │   ├── components/       # components เฉพาะของหน้า home
│   │   │   ├── home.component.ts
│   │   │   ├── home.module.ts
│   │   │   └── home-routing.module.ts
│   │   └── ...
│
│   ├── app-routing.module.ts     # รวม routes ทั้งหมด
│   ├── app.component.ts
│   └── app.module.ts
│
├── assets/                       # รูปภาพ, ไอคอน, ไฟล์ static
├── environments/                # ไฟล์ config สำหรับ dev/prod
│   ├── environment.ts
│   └── environment.prod.ts
├── styles/                       # SCSS/CSS global styles
│   └── main.scss
└── main.ts

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🧠 รายละเอียดแต่ละโฟลเดอร์&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;โฟลเดอร์&lt;/th&gt;
&lt;th&gt;หน้าที่&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;core/&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;สำหรับ services ที่ใช้ทั่วแอป เช่น &lt;code&gt;AuthService&lt;/code&gt;, &lt;code&gt;ApiService&lt;/code&gt;, &lt;code&gt;TokenInterceptor&lt;/code&gt;, &lt;code&gt;AuthGuard&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;shared/&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;สำหรับ components/pipes/directives ที่ใช้ร่วมกัน เช่น &lt;code&gt;ButtonComponent&lt;/code&gt;, &lt;code&gt;DatePipe&lt;/code&gt;, &lt;code&gt;CardComponent&lt;/code&gt;, รวมถึง types หรือ interfaces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;pages/&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;แต่ละหน้าแยกเป็น module ชัดเจน เช่น &lt;code&gt;/home&lt;/code&gt;, &lt;code&gt;/login&lt;/code&gt;, &lt;code&gt;/dashboard&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;models/&lt;/strong&gt; หรือ &lt;strong&gt;types/&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;สำหรับสร้าง interface ของข้อมูล เช่น &lt;code&gt;User&lt;/code&gt;, &lt;code&gt;Product&lt;/code&gt;, &lt;code&gt;Order&lt;/code&gt;, ใช้ภายใต้ &lt;code&gt;shared/models/&lt;/code&gt; หรือ &lt;code&gt;shared/types/&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;routes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;มักอยู่ใน &lt;code&gt;app-routing.module.ts&lt;/code&gt; และแยกเป็น &lt;code&gt;xxx-routing.module.ts&lt;/code&gt; สำหรับแต่ละ module&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;✅ ตัวอย่างการตั้งชื่อ&lt;/p&gt;

&lt;p&gt;📄 shared/models/user.model.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface User {
  id: string;
  username: string;
  email: string;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📁 pages/home/home.component.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component } from '@angular/core';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
})
export class HomeComponent {}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📁 app-routing.module.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const routes: Routes = [
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  {
    path: 'home',
    loadChildren: () =&amp;gt;
      import('./pages/home/home.module').then((m) =&amp;gt; m.HomeModule),
  },
  // ...
];

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📁 core/services/api.service.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Injectable({ providedIn: 'root' })
export class ApiService {
  constructor(private http: HttpClient) {}

  get&amp;lt;T&amp;gt;(url: string): Observable&amp;lt;T&amp;gt; {
    return this.http.get&amp;lt;T&amp;gt;(url);
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 สรุป&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;สิ่งที่คุณต้องการ&lt;/th&gt;
&lt;th&gt;อยู่ตรงไหนในโครงสร้าง&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Components&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;shared/components/&lt;/code&gt;, หรือ &lt;code&gt;pages/[page]/components/&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Routes&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;app-routing.module.ts&lt;/code&gt;, &lt;code&gt;xxx-routing.module.ts&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Types / Interfaces&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;shared/models/&lt;/code&gt; หรือ &lt;code&gt;shared/types/&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Services&lt;/td&gt;
&lt;td&gt;&lt;code&gt;core/services/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pages&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pages/[pagename]/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ถ้าคุณต้องการใช้ Angular CLI เพื่อ generate โครงสร้างโปรเจกต์ที่ดีตั้งแต่ต้น พร้อมกับ routing แยกหน้า (lazy loading), services, และ components ได้อัตโนมัติ&lt;/p&gt;

&lt;p&gt;✅ เริ่มต้นสร้างโปรเจกต์ Angular&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng new my-angular-app --routing --style=scss

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;--routing: สร้างไฟล์ app-routing.module.ts ให้อัตโนมัติ&lt;/p&gt;

&lt;p&gt;--style=scss: เลือกใช้ SCSS แทน CSS&lt;/p&gt;

&lt;p&gt;เข้าไปในโปรเจกต์:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd my-angular-app

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ 1. สร้างหน้า (page) แบบ Lazy Load + Routing&lt;br&gt;
เช่น หน้า Home&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate module pages/home --route home --module app.module

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Angular จะสร้างให้อัตโนมัติแบบ lazy loading:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/app/pages/home/
├── home-routing.module.ts
├── home.module.ts
└── home.component.ts

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔁 สร้างหน้าต่อไป เช่น Login, Dashboard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate module pages/login --route login --module app.module
ng generate module pages/dashboard --route dashboard --module app.module

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ 2. สร้าง Shared Components&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate module shared/shared --module app
ng generate component shared/components/button
ng generate component shared/components/card

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;คุณสามารถ export component ใน shared.module.ts ได้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@NgModule({
  declarations: [ButtonComponent, CardComponent],
  exports: [ButtonComponent, CardComponent],
})
export class SharedModule {}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ 3. สร้าง Services&lt;br&gt;
สร้างใน core/services/:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate module core/core --module app
ng generate service core/services/api
ng generate service core/services/auth

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;services&lt;/code&gt; เหล่านี้จะเป็น singleton ถ้าเพิ่ม providedIn: 'root' (default)&lt;/p&gt;

&lt;p&gt;✅ 4. สร้าง Types หรือ Interfaces&lt;br&gt;
สร้างไฟล์ใน src/app/shared/models/:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// user.model.ts
export interface User {
  id: number;
  name: string;
  email: string;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ 5. สร้าง Guards, Interceptors (optionally)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate guard core/guards/auth
ng generate interceptor core/interceptors/token

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📦 ตัวอย่างโครงสร้างที่ได้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/app/
├── core/
│   ├── services/
│   │   ├── api.service.ts
│   │   └── auth.service.ts
│   ├── guards/
│   ├── interceptors/
│   └── core.module.ts
│
├── shared/
│   ├── components/
│   │   ├── button/
│   │   └── card/
│   ├── models/
│   │   └── user.model.ts
│   └── shared.module.ts
│
├── pages/
│   ├── home/
│   ├── login/
│   └── dashboard/
│
├── app-routing.module.ts
└── app.module.ts

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀 พร้อมใช้งาน!&lt;br&gt;
รันโปรเจกต์:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng serve

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เปิดเบราว์เซอร์ที่ &lt;a href="http://localhost:4200/home" rel="noopener noreferrer"&gt;http://localhost:4200/home&lt;/a&gt; หรือ /login, /dashboard ได้เลย&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>RxJS vs Redux Thunk: เลือกอะไรดี? อธิบายแบบเข้าใจง่าย พร้อมตัวอย่าง</title>
      <dc:creator>c_nooknook_daily_prompt</dc:creator>
      <pubDate>Wed, 25 Jun 2025 05:36:26 +0000</pubDate>
      <link>https://dev.to/nooknookwork/rxjs-vs-redux-thunk-eluuekaairdii-thibaayaebbekhaaaicchngaay-phrmtawyaang-4j8i</link>
      <guid>https://dev.to/nooknookwork/rxjs-vs-redux-thunk-eluuekaairdii-thibaayaebbekhaaaicchngaay-phrmtawyaang-4j8i</guid>
      <description>&lt;p&gt;&lt;strong&gt;RxJS (ย่อมาจาก Reactive Extensions for JavaScript)&lt;/strong&gt; คือ ไลบรารีสำหรับจัดการ asynchronous data stream อย่างมีประสิทธิภาพและยืดหยุ่นมาก โดยใช้แนวคิดของ Reactive Programming &lt;/p&gt;

&lt;p&gt;🧠 &lt;strong&gt;แนวคิดหลักของ RxJS&lt;/strong&gt;&lt;br&gt;
🔄 "Everything is a stream"&lt;br&gt;
ข้อมูลต่าง ๆ ไม่ว่าจะเป็น click, typing, HTTP response, หรือ timer — ล้วนเป็น stream ได้&lt;/p&gt;

&lt;p&gt;Stream คือ ลำดับของค่าที่เกิดขึ้นตามเวลา&lt;/p&gt;

&lt;p&gt;🔧 &lt;strong&gt;RxJS ใช้ทำอะไร?&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;การใช้งานทั่วไป&lt;/th&gt;
&lt;th&gt;ตัวอย่าง&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;จัดการ event อย่างซับซ้อน&lt;/td&gt;
&lt;td&gt;พวก click หลายครั้ง, debounce&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ควบคุม API call&lt;/td&gt;
&lt;td&gt;cancel request, retry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;สร้าง pipeline ที่สามารถเปลี่ยนแปลง/กรองข้อมูล&lt;/td&gt;
&lt;td&gt;map, filter, merge, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ผสานหลาย stream เข้าด้วยกัน&lt;/td&gt;
&lt;td&gt;combineLatest, merge, zip&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reactive UI / Form&lt;/td&gt;
&lt;td&gt;ทำงานร่วมกับ Angular Reactive Forms ได้ดี&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🧱 &lt;strong&gt;ส่วนประกอบหลักของ RxJS&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ส่วนประกอบ&lt;/th&gt;
&lt;th&gt;ความหมาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Observable&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ตัวแทนของ stream (เหมือน Promise ที่ส่งข้อมูลได้หลายค่า)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Observer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ผู้ที่ subscribe เพื่อรับข้อมูลจาก Observable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operators&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ฟังก์ชันที่เปลี่ยนแปลง stream เช่น &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;debounceTime&lt;/code&gt;, &lt;code&gt;mergeMap&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Subject&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;เป็นทั้ง Observable และ Observer (ใช้ส่งข้อมูลจาก component ไปยังอื่นๆ)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Subscription&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ตัวแทนของการเชื่อมต่อ (subscribe) ที่สามารถ unsubscribe ได้&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;📦 ตัวอย่างใช้งานง่ายๆ&lt;/p&gt;

&lt;p&gt;🔔 สร้าง Observable และ subscribe&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Observable } from 'rxjs'

const observable = new Observable((subscriber) =&amp;gt; {
  subscriber.next('Hello')
  subscriber.next('World')
  subscriber.complete()
})

observable.subscribe({
  next: (val) =&amp;gt; console.log(val),
  complete: () =&amp;gt; console.log('Done'),
})
// 👉 Output:
// Hello
// World
// Done

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⌨️ ใช้กับ DOM event&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { fromEvent } from 'rxjs'

const clicks$ = fromEvent(document, 'click')
clicks$.subscribe(event =&amp;gt; console.log(event))

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔄 ใช้ Operator เช่น map และ filter&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { of } from 'rxjs'
import { map, filter } from 'rxjs/operators'

of(1, 2, 3, 4, 5).pipe(
  filter(x =&amp;gt; x % 2 === 1),
  map(x =&amp;gt; x * 10)
).subscribe(val =&amp;gt; console.log(val))
// 👉 Output: 10, 30, 50

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📍 &lt;strong&gt;RxJS นิยมใช้ในไหน?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Angular: ใช้ RxJS เป็นแกนหลักของ HTTP, Form, Router&lt;/li&gt;
&lt;li&gt;✅ ใช้ใน React ได้ด้วย โดยใช้ร่วมกับ rxjs-hooks หรือ state management แบบ reactive&lt;/li&gt;
&lt;li&gt;✅ ใช้ใน Node.js / Backend ที่ต้องการจัดการ async หลายแหล่ง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔚 &lt;strong&gt;สรุป&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;คำถาม&lt;/th&gt;
&lt;th&gt;คำตอบสั้น&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RxJS คืออะไร&lt;/td&gt;
&lt;td&gt;ไลบรารีสำหรับจัดการ asynchronous data ด้วยแนวคิด reactive programming&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ทำอะไร&lt;/td&gt;
&lt;td&gt;จัดการ event, async stream, UI updates, API call ฯลฯ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เหมาะกับใคร&lt;/td&gt;
&lt;td&gt;คนที่เจอ async/stream หลายอย่างซ้อนกัน และต้องการเขียนโค้ดให้สะอาด&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;RxJS กับ Redux Thunk มีเป้าหมายและแนวคิดต่างกัน แม้ทั้งคู่จะใช้ในการจัดการ asynchronous logic ได้เหมือนกันก็ตาม&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🧠 เปรียบเทียบโดยสรุป: RxJS vs Redux Thunk&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;คุณสมบัติ&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Redux Thunk&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;RxJS&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;แนวคิดหลัก&lt;/td&gt;
&lt;td&gt;Imperative + async/await&lt;/td&gt;
&lt;td&gt;Reactive Programming (ทุกอย่างคือ stream)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้งาน&lt;/td&gt;
&lt;td&gt;จัดการ async logic ใน Redux (เช่น fetch API)&lt;/td&gt;
&lt;td&gt;จัดการ stream ที่ต่อเนื่อง เช่น event, input, timer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เหมาะกับ&lt;/td&gt;
&lt;td&gt;งานที่ async ง่ายๆ เช่น API call ใน Redux&lt;/td&gt;
&lt;td&gt;งานที่ซับซ้อน เช่น auto-complete, live search, cancel request, UI ที่เปลี่ยนตามเวลา&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;syntax&lt;/td&gt;
&lt;td&gt;ใช้ async/await, if/else, try/catch ง่าย&lt;/td&gt;
&lt;td&gt;ใช้ operators เช่น &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;switchMap&lt;/code&gt;, ต้องเรียนรู้เพิ่มเติม&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;integration&lt;/td&gt;
&lt;td&gt;ทำงานเฉพาะใน Redux (กับ store และ dispatch)&lt;/td&gt;
&lt;td&gt;ใช้ได้ทุกที่: React, Angular, Node.js, ไม่ต้องใช้ Redux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;learning curve&lt;/td&gt;
&lt;td&gt;ง่ายกว่า&lt;/td&gt;
&lt;td&gt;ยากกว่า&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cancel async ได้ไหม&lt;/td&gt;
&lt;td&gt;ยากหรือทำไม่ได้&lt;/td&gt;
&lt;td&gt;ทำได้ง่าย (ผ่าน &lt;code&gt;switchMap&lt;/code&gt;, &lt;code&gt;takeUntil&lt;/code&gt;, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ร่วมกับ framework&lt;/td&gt;
&lt;td&gt;React + Redux&lt;/td&gt;
&lt;td&gt;Angular (native), React (ได้ แต่ต้องวางแผนดี)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;📦 ตัวอย่างงานที่เหมาะกับแต่ละตัว&lt;/p&gt;

&lt;p&gt;✅ เหมาะกับ Redux Thunk&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;งานที่เหมาะสม&lt;/th&gt;
&lt;th&gt;เหตุผล&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;โหลดข้อมูลจาก API&lt;/td&gt;
&lt;td&gt;ใช้ async/await ได้ง่าย&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;จัดการ auth เช่น login/logout&lt;/td&gt;
&lt;td&gt;ง่ายต่อการจัด flow และ dispatch หลาย action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI สถานะ loading/error/success ที่ไม่ซับซ้อน&lt;/td&gt;
&lt;td&gt;เขียน reducer ได้ตรงไปตรงมา&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Form submit ที่ทำงานทีละรอบ&lt;/td&gt;
&lt;td&gt;ไม่ต้อง cancel หรือ debounce&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;✅ เหมาะกับ RxJS&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;งานที่เหมาะสม&lt;/th&gt;
&lt;th&gt;เหตุผล&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Auto-complete หรือ search ที่ debounce และ cancel previous request&lt;/td&gt;
&lt;td&gt;ใช้ &lt;code&gt;debounceTime&lt;/code&gt; + &lt;code&gt;switchMap&lt;/code&gt; ง่ายมาก&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live data / real-time UI&lt;/td&gt;
&lt;td&gt;ใช้ &lt;code&gt;interval&lt;/code&gt;, &lt;code&gt;websocket&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt; ได้ดี&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ดักจับ input หลายอย่างพร้อมกัน เช่น keydown + mouse + API + timer&lt;/td&gt;
&lt;td&gt;ผสาน stream ด้วย &lt;code&gt;combineLatest&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;zip&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cancel async ได้ง่าย&lt;/td&gt;
&lt;td&gt;ทำได้ผ่าน stream control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ต้อง reuse pipeline หลายจุด&lt;/td&gt;
&lt;td&gt;เขียน operator chain ไว้ใช้งานซ้ำได้&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;💡 ถ้า logic มีลักษณะ "หลาย async ซ้อนกัน", "ต้อง cancel บางอัน", หรือ "ควบคุม event หลายแหล่งพร้อมกัน", RxJS เหมาะกว่า&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ลักษณะโปรเจกต์ของคุณ&lt;/th&gt;
&lt;th&gt;แนะนำใช้&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API call ธรรมดา, login/logout, loading/error ง่ายๆ&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Redux Thunk&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;มี live search, debounce, cancel async, stream ซับซ้อน&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RxJS&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ Angular&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;RxJS&lt;/strong&gt; โดยธรรมชาติ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ React + Redux&lt;/td&gt;
&lt;td&gt;เริ่มจาก &lt;strong&gt;Thunk&lt;/strong&gt;, ถ้า logic ซับซ้อนค่อยพิจารณา RxJS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>ติวสอบสัมภาษณ์งาน Java เบื้องต้น ฉบับ มือใหม่ [2]</title>
      <dc:creator>c_nooknook_daily_prompt</dc:creator>
      <pubDate>Wed, 25 Jun 2025 04:19:03 +0000</pubDate>
      <link>https://dev.to/nooknookwork/tiwsbsamphaasn-java-ebuuengtn-chbab-muueaihm-2-1n76</link>
      <guid>https://dev.to/nooknookwork/tiwsbsamphaasn-java-ebuuengtn-chbab-muueaihm-2-1n76</guid>
      <description>&lt;p&gt;&lt;strong&gt;Spring Framework เบื้องต้น&lt;/strong&gt;&lt;br&gt;
Java Spring Boot การ build project สามารถทำได้หลายรูปแบบ โดยขึ้นอยู่กับ build tool ที่ใช้ ซึ่งที่นิยมมากที่สุดมี 2 ตัวหลัก ๆ คือ&lt;/p&gt;

&lt;p&gt;✅ 1. Gradle&lt;br&gt;
✅ 2. Maven&lt;/p&gt;

&lt;p&gt;ทั้งสอง เกี่ยวข้องโดยตรง กับกระบวนการ build, run, test, package, และ deploy ของ Spring Boot project&lt;/p&gt;

&lt;p&gt;🔧 Gradle และ Maven คืออะไร?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;รายการ&lt;/th&gt;
&lt;th&gt;Gradle&lt;/th&gt;
&lt;th&gt;Maven&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;รูปแบบ config&lt;/td&gt;
&lt;td&gt;DSL: ใช้ Groovy/ Kotlin DSL&lt;/td&gt;
&lt;td&gt;XML (pom.xml)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ความยืดหยุ่น&lt;/td&gt;
&lt;td&gt;สูง (custom script ได้ง่าย)&lt;/td&gt;
&lt;td&gt;ต่ำกว่า แต่ชัดเจนกว่า&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ความเร็วในการ build&lt;/td&gt;
&lt;td&gt;เร็วกว่า Maven (ใช้ cache)&lt;/td&gt;
&lt;td&gt;ช้ากว่า Gradle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning Curve&lt;/td&gt;
&lt;td&gt;สูงขึ้นนิดหน่อย&lt;/td&gt;
&lt;td&gt;เรียนรู้ได้เร็วกว่า&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;วิธีการ build Project (Build ได้กี่แบบ?)&lt;/p&gt;

&lt;p&gt;👉 หากใช้ Gradle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew build         # สร้าง JAR
./gradlew bootRun       # รันแอปแบบ development
./gradlew bootJar       # สร้างไฟล์ JAR เฉพาะ Spring Boot
./gradlew clean         # ลบ build เดิมก่อน

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 หากใช้ Maven:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mvn clean install       # สร้าง JAR และติดตั้งไว้ใน local repo
mvn spring-boot:run     # รันแอป
mvn package             # สร้าง JAR

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📦 ผลลัพธ์ของการ Build&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ได้เป็นไฟล์ .jar หรือ .war (ขึ้นอยู่กับ config)&lt;/li&gt;
&lt;li&gt;สามารถนำไป deploy ได้ทันที (Spring Boot เป็น self-contained)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎯 สรุปว่า Gradle/Maven เกี่ยวข้องอย่างไร?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;สิ่งที่เกี่ยวข้อง&lt;/th&gt;
&lt;th&gt;คำอธิบาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🔗 &lt;strong&gt;Build Tool&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Spring Boot ใช้ Maven/Gradle เพื่อจัดการ dependency, build, run และ deploy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚙️ &lt;strong&gt;Dependency Management&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Maven: ใช้ pom.xml, Gradle: ใช้ build.gradle เพื่อกำหนดไลบรารี&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📄 &lt;strong&gt;Script Configuration&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ใช้ระบุเวอร์ชัน Spring Boot, plugins และ tasks สำหรับ build&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;✅ สรุปสุดท้าย&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring Boot build ได้หลายแบบ เช่น JAR, WAR, native image (GraalVM)&lt;/li&gt;
&lt;li&gt;ต้องใช้ build tool เช่น Gradle หรือ Maven ในการจัดการขั้นตอนต่าง ๆ&lt;/li&gt;
&lt;li&gt;Gradle กับ Maven ทำหน้าที่คล้ายกันแต่มี syntax และประสิทธิภาพที่ต่างกันเล็กน้อย&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🌟 &lt;strong&gt;GraalVM คืออะไร?&lt;/strong&gt;&lt;br&gt;
GraalVM คือ High-Performance Virtual Machine ที่สามารถรันหลายภาษาได้ (เช่น Java, JavaScript, Python, Ruby ฯลฯ) โดยมี จุดเด่น คือ:&lt;/p&gt;

&lt;p&gt;✅ รองรับการ compile Java application ให้กลายเป็น Native Executable (AOT Compile)&lt;br&gt;
✅ ทำงานเร็วกว่า JVM แบบปกติในบางกรณี&lt;br&gt;
✅ ใช้ memory น้อยลง&lt;br&gt;
✅ Startup time ไวมาก (เช่น 0.01 วินาที เทียบกับ 2-3 วินาทีของ JVM ปกติ)&lt;/p&gt;

&lt;p&gt;GraalVM ต่างจาก JVM ปกติยังไง?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ประเด็น&lt;/th&gt;
&lt;th&gt;JVM ปกติ (OpenJDK)&lt;/th&gt;
&lt;th&gt;GraalVM (Native Image)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🛠️ Compile Type&lt;/td&gt;
&lt;td&gt;JIT (Just-In-Time)&lt;/td&gt;
&lt;td&gt;AOT (Ahead-Of-Time)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚡ Startup Time&lt;/td&gt;
&lt;td&gt;ช้า (warm-up ก่อน)&lt;/td&gt;
&lt;td&gt;เร็วมาก (เกือบทันที)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧠 Memory Usage&lt;/td&gt;
&lt;td&gt;ใช้เยอะ&lt;/td&gt;
&lt;td&gt;ใช้น้อย&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔁 Compatible Libs&lt;/td&gt;
&lt;td&gt;รองรับทุก lib Java&lt;/td&gt;
&lt;td&gt;ต้องใช้ lib ที่ support AOT เท่านั้น&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧳 ขนาดไฟล์ Executable&lt;/td&gt;
&lt;td&gt;ไม่สามารถ run ได้เอง (ต้องใช้ JVM)&lt;/td&gt;
&lt;td&gt;เป็น binary พร้อม run ได้เลย&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🚀 GraalVM กับ Spring Boot&lt;br&gt;
Spring Boot สามารถทำงานร่วมกับ GraalVM ได้ผ่าน Spring Native หรือ Spring Boot 3.x ขึ้นไปที่ใช้ AOT Processing โดยตรง&lt;/p&gt;

&lt;p&gt;ตัวอย่าง Build แบบ Native:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew bootBuildImage --builder paketobuildpacks/builder:tiny

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หรือใช้ GraalVM ตรง ๆ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;native-image -jar your-app.jar

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ได้ผลลัพธ์เป็นไฟล์ .exe หรือ binary ที่สามารถ run ได้โดยไม่ต้องติดตั้ง Java&lt;/p&gt;

&lt;p&gt;📌 &lt;strong&gt;ใช้ GraalVM ตอนไหนถึงจะดี?&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;เหมาะกับ&lt;/th&gt;
&lt;th&gt;เพราะว่า&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;💻 Microservices&lt;/td&gt;
&lt;td&gt;ต้องการ startup เร็ว, ใช้ memory น้อย&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🖥️ CLI tools&lt;/td&gt;
&lt;td&gt;ต้องการ build เป็น binary ขนาดเล็ก&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;☁️ Serverless&lt;/td&gt;
&lt;td&gt;ช่วยลด cold-start time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📱 Embedded App&lt;/td&gt;
&lt;td&gt;มี resource จำกัด&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;📦 แต่ข้อควรระวัง&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ไม่รองรับ Reflection บางแบบ (เช่นการใช้ Class.forName()) ต้องกำหนดล่วงหน้า&lt;/li&gt;
&lt;li&gt;การ build นานมาก (บางครั้งหลักนาที)&lt;/li&gt;
&lt;li&gt;ต้องเขียนโค้ดให้ AOT-friendly&lt;/li&gt;
&lt;li&gt;ไม่รองรับทุก third-party lib โดยเฉพาะที่ใช้ dynamic code&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;คำถาม&lt;/th&gt;
&lt;th&gt;คำตอบ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GraalVM คืออะไร?&lt;/td&gt;
&lt;td&gt;VM ที่ compile Java เป็น native binary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ต่างจาก JVM ปกติยังไง?&lt;/td&gt;
&lt;td&gt;เร็วกว่า, ใช้ memory น้อยกว่า, run ได้ทันที&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้กับ Spring Boot ได้ไหม?&lt;/td&gt;
&lt;td&gt;ได้ โดยใช้ Spring Native หรือ Spring Boot 3.x+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ควรใช้เมื่อไหร่?&lt;/td&gt;
&lt;td&gt;เมื่อ performance สำคัญ เช่นใน Microservices หรือ Serverless&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🔍 &lt;strong&gt;AOT คืออะไร?&lt;/strong&gt;&lt;br&gt;
AOT = Ahead-Of-Time compilation&lt;br&gt;
คือการ compile โค้ดล่วงหน้า (ก่อน runtime) ให้เป็น binary (เครื่องอ่านได้เลย)&lt;br&gt;
ต่างจาก JIT ที่ compile ตอน runtime&lt;/p&gt;

&lt;p&gt;📦 ตัวอย่าง:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;แบบ&lt;/th&gt;
&lt;th&gt;ความหมาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;✅ &lt;strong&gt;AOT (Ahead-of-Time)&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Compile เป็น binary ก่อนรัน เช่น GraalVM Native Image&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❌ &lt;strong&gt;JIT (Just-in-Time)&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Compile ระหว่างรัน เช่น JVM ปกติ (OpenJDK, HotSpot)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🚀 ทำไม AOT เร็ว?&lt;br&gt;
เพราะมัน ไม่ต้องตีความ หรือ compile ซ้ำ ขณะรันโปรแกรม&lt;br&gt;
จึงได้ผลลัพธ์:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚡ Startup เร็ว&lt;/li&gt;
&lt;li&gt;🧠 ใช้ memory น้อยลง&lt;/li&gt;
&lt;li&gt;🐳 เหมาะกับ container, serverless&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧩 AOT-Friendly คืออะไร?&lt;/p&gt;

&lt;p&gt;โค้ดของเราต้องเขียนในแบบที่ "สามารถ compile ล่วงหน้า" ได้ โดยไม่ต้องพึ่ง runtime processing หรือ reflection ที่ไม่แน่นอน&lt;/p&gt;

&lt;p&gt;❌ ตัวอย่าง "ไม่ AOT-friendly"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Class.forName("com.example.MyClass"); // ใช้ reflection

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Autowired
private Object someBean; // ใช้ dynamic injection แบบที่ compiler เดาไม่ได้

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;พวกนี้ GraalVM จะไม่สามารถ "คาดเดา" ได้ล่วงหน้า ทำให้ build ไม่ผ่าน หรือรันไม่ได้&lt;/p&gt;

&lt;p&gt;✅ ตัวอย่าง "AOT-friendly"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Autowired
private MyService myService; // แบบเจาะจง class
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หรือใช้ annotation ที่ GraalVM รองรับ เช่น @RestController, @ConfigurationProperties แบบ static&lt;/p&gt;

&lt;p&gt;📘 ใน Spring Boot 3+&lt;/p&gt;

&lt;p&gt;Spring Boot 3.x ใช้ Spring AOT Engine เพื่อ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;วิเคราะห์โค้ดทั้งหมด&lt;/li&gt;
&lt;li&gt;Generate code/metadata ที่ GraalVM เข้าใจได้&lt;/li&gt;
&lt;li&gt;ลด runtime reflection ลง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ สรุป&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;หัวข้อ&lt;/th&gt;
&lt;th&gt;ความหมาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AOT&lt;/td&gt;
&lt;td&gt;Compile โค้ดล่วงหน้าก่อนรัน&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AOT-friendly&lt;/td&gt;
&lt;td&gt;โค้ดที่เขียนแบบ static ชัดเจน ไม่มี reflection หรือ dynamic code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ทำไมต้องสนใจ&lt;/td&gt;
&lt;td&gt;เพราะ GraalVM ต้องการ compile ล่วงหน้าให้เร็วและเบา&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spring Boot 3&lt;/td&gt;
&lt;td&gt;รองรับ AOT และ Native Image เต็มรูปแบบ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ตัวอย่างการใช้ Spring Boot สร้าง REST Controller ง่าย ๆ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello from Spring Boot!";
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;@RestController คือการประกาศว่า Class นี้เป็น Controller แบบ REST&lt;/p&gt;

&lt;p&gt;@GetMapping คือการแมป HTTP GET กับ method&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency Injection (DI)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
public class UserService {
    // business logic
}

@RestController
public class UserController {
    private final UserService userService;

    // Constructor Injection
    public UserController(UserService userService) {
        this.userService = userService;
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;JDBC (Java Database Connectivity)&lt;/strong&gt;&lt;br&gt;
JDBC คือ API มาตรฐานของ Java สำหรับเชื่อมต่อและสั่งงานฐานข้อมูลแบบ relational เช่น MySQL, PostgreSQL&lt;/p&gt;

&lt;p&gt;ตัวอย่าง JDBC เชื่อมต่อฐานข้อมูล&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;String url = "jdbc:mysql://localhost:3306/mydb";
String user = "root";
String password = "password";

try (Connection conn = DriverManager.getConnection(url, user, password)) {
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("SELECT * FROM users");

    while (rs.next()) {
        System.out.println(rs.getString("username"));
    }
} catch (SQLException e) {
    e.printStackTrace();
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🌐 &lt;strong&gt;REST API&lt;/strong&gt;&lt;br&gt;
REST (Representational State Transfer) คือสถาปัตยกรรมสำหรับสร้าง Web Services ที่ใช้ HTTP Method (GET, POST, PUT, DELETE) ในการจัดการ Resource&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTP Methods ที่ควรรู้&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;ใช้ทำอะไร?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;ดึงข้อมูล&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST&lt;/td&gt;
&lt;td&gt;สร้างข้อมูลใหม่&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PUT&lt;/td&gt;
&lt;td&gt;แก้ไขข้อมูล&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DELETE&lt;/td&gt;
&lt;td&gt;ลบข้อมูล&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ตัวอย่าง REST API ด้วย Spring Boot&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
@RequestMapping("/api/users")
public class UserRestController {

    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        // return user by id
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        // create user
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 Lombok คืออะไร?&lt;br&gt;
Lombok เป็นไลบรารีของ Java ที่ช่วยลดโค้ดซ้ำซ้อน เช่น getter, setter, constructor, toString() โดยอาศัย annotation-based code generation ที่ compile-time&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lombok Annotations ที่ใช้บ่อย&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Annotation&lt;/th&gt;
&lt;th&gt;ทำหน้าที่&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;@Getter&lt;/code&gt;, &lt;code&gt;@Setter&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;สร้าง getter/setter อัตโนมัติ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ToString&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;สร้างเมธอด &lt;code&gt;toString()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@EqualsAndHashCode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;สร้าง &lt;code&gt;equals()&lt;/code&gt; และ &lt;code&gt;hashCode()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@NoArgsConstructor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;สร้าง constructor แบบไม่มี argument&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@AllArgsConstructor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;สร้าง constructor ที่รับทุก field&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@RequiredArgsConstructor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;สร้าง constructor สำหรับ field ที่เป็น &lt;code&gt;final&lt;/code&gt; หรือ &lt;code&gt;@NonNull&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;รวม &lt;code&gt;@Getter&lt;/code&gt;, &lt;code&gt;@Setter&lt;/code&gt;, &lt;code&gt;@ToString&lt;/code&gt;, &lt;code&gt;@EqualsAndHashCode&lt;/code&gt;, &lt;code&gt;@RequiredArgsConstructor&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Builder&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ใช้สร้าง object แบบ builder pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Value&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ทำให้ class เป็น immutable (เหมือน &lt;code&gt;final&lt;/code&gt; + &lt;code&gt;@Data&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ตัวอย่างการใช้ Lombok&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import lombok.Data;
import lombok.Builder;

@Data
@Builder
public class User {
    private String name;
    private int age;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ผลลัพธ์ที่ได้: class นี้จะมี getter, setter, toString, equals, hashCode และสามารถสร้าง object แบบนี้ได้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User user = User.builder()
                .name("Alice")
                .age(25)
                .build();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;strong&gt;Annotation ใน Java คือชนิดพิเศษของ interface&lt;/strong&gt;&lt;br&gt;
❌ ไม่ใช่ class (class ธรรมดา)&lt;br&gt;
❌ ไม่ใช่ function&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Annotation = ป้ายกำกับ (label) ที่อธิบายว่า class หรือ method นี้ "มีความหมายพิเศษ"&lt;/li&gt;
&lt;li&gt;Annotation คือคำสั่งพิเศษที่ขึ้นต้นด้วย @ ใช้เพื่อ แนบ metadata (ข้อมูลเพิ่มเติม) ให้กับ class, method, field ฯลฯ&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ไม่ส่งผลต่อ logic โดยตรง แต่สามารถใช้ร่วมกับ framework, tooling, หรือ compile-time processing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ใน Java ทุก annotation ถูกสร้างด้วยคีย์เวิร์ด &lt;a class="mentioned-user" href="https://dev.to/interface"&gt;@interface&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ซึ่งหมายความว่า annotation เป็นชนิดหนึ่งของ interface ที่มี metadata เท่านั้น&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;เบื้องหลัง &lt;a class="mentioned-user" href="https://dev.to/interface"&gt;@interface&lt;/a&gt; → Java จะสร้าง interface พิเศษ ที่เก็บเฉพาะ "ค่ากำกับ (metadata)" เท่านั้น ไม่มี logic หรือพฤติกรรมแบบ class ทั่วไป&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;สรุปเปรียบเทียบ&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;สิ่งที่เปรียบเทียบ&lt;/th&gt;
&lt;th&gt;class&lt;/th&gt;
&lt;th&gt;interface&lt;/th&gt;
&lt;th&gt;annotation (&lt;code&gt;@interface&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;มี logic ได้ไหม&lt;/td&gt;
&lt;td&gt;✅ ได้&lt;/td&gt;
&lt;td&gt;❌ ไม่ได้&lt;/td&gt;
&lt;td&gt;❌ ไม่ได้&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ &lt;code&gt;@interface&lt;/code&gt; ได้ไหม&lt;/td&gt;
&lt;td&gt;❌ ไม่ได้&lt;/td&gt;
&lt;td&gt;❌ ไม่ได้&lt;/td&gt;
&lt;td&gt;✅ ได้&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;มี &lt;code&gt;method body&lt;/code&gt; ได้ไหม&lt;/td&gt;
&lt;td&gt;✅ ได้&lt;/td&gt;
&lt;td&gt;❌ ไม่ได้&lt;/td&gt;
&lt;td&gt;❌ ไม่ได้&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้สร้าง object ได้ไหม&lt;/td&gt;
&lt;td&gt;✅ ได้&lt;/td&gt;
&lt;td&gt;❌ ไม่ได้&lt;/td&gt;
&lt;td&gt;❌ ไม่ได้&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ถูก JVM อ่านแบบ metadata ไหม&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ ใช่&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ตัวอย่าง&lt;/td&gt;
&lt;td&gt;&lt;code&gt;public class MyClass {}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;interface MyService {}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@interface MyAnnotation {}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;แล้ว annotation ใช้ยังไง?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@MyAnnotation(value = "dev")
public class Demo {}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;JVM จะไม่เรียก MyAnnotation แบบ object แต่จะเก็บข้อมูลนี้เป็น metadata&lt;/li&gt;
&lt;li&gt;เราสามารถใช้ reflection อ่าน metadata เหล่านี้ได้ใน runtime&lt;/li&gt;
&lt;li&gt;หรือ framework เช่น Spring, JUnit, Hibernate จะใช้ annotation เพื่อกำหนดพฤติกรรม&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧠 &lt;strong&gt;สรุปสุดท้ายจำง่าย:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❓ Annotation คือ class ไหม?&lt;/li&gt;
&lt;li&gt;🔸 ❌ ไม่ใช่ class&lt;/li&gt;
&lt;li&gt;🔹 ✅ เป็น interface แบบพิเศษ (ประกาศด้วย &lt;a class="mentioned-user" href="https://dev.to/interface"&gt;@interface&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;🔸 📌 ใช้เพื่อแนบ metadata ไม่ได้มี logic หรือสร้าง instance แบบ class ได้&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Spring Boot Annotations ที่ควรรู้&lt;/strong&gt;&lt;br&gt;
ตัวอย่าง Annotation ที่ใช้บ่อยใน Java&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Annotation&lt;/th&gt;
&lt;th&gt;ใช้ทำอะไร&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Override&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;บอกว่า method นี้ override มาจาก superclass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Deprecated&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;เตือนว่า method/class นี้เลิกใช้แล้ว&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@SuppressWarnings&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ปิด warning จาก compiler&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Annotation ที่ใช้บ่อยใน Spring Framework&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Annotation&lt;/th&gt;
&lt;th&gt;ใช้ทำอะไร&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Component&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;บอกว่า class นี้เป็น bean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ระบุว่าเป็น service layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Repository&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ระบุว่าเป็น repository สำหรับ JPA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Autowired&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ให้ Spring inject dependency อัตโนมัติ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;@RequestMapping&lt;/code&gt;, &lt;code&gt;@GetMapping&lt;/code&gt;, &lt;code&gt;@PostMapping&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;ใช้ระบุเส้นทาง HTTP ใน Controller&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@RestController&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;รวม &lt;code&gt;@Controller&lt;/code&gt; + &lt;code&gt;@ResponseBody&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;@Configuration&lt;/code&gt;, &lt;code&gt;@Bean&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;ใช้กำหนด bean ด้วยมือ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🔽 Annotation ระดับ Class&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Annotation&lt;/th&gt;
&lt;th&gt;คำอธิบาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@SpringBootApplication&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;รวบรวม &lt;code&gt;@Configuration&lt;/code&gt;, &lt;code&gt;@EnableAutoConfiguration&lt;/code&gt;, &lt;code&gt;@ComponentScan&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@RestController&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ประกาศว่าเป็น REST API controller&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;สำหรับ class ที่เป็น business logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Repository&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;สำหรับ class ที่ติดต่อ database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Component&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ใช้กับ bean ทั่วไป&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Configuration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ใช้สร้าง Java config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@EnableAutoConfiguration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ให้ Spring ตั้งค่าทุกอย่างให้อัตโนมัติ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🔼 Annotation ระดับ Method / Field&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Annotation&lt;/th&gt;
&lt;th&gt;คำอธิบาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Autowired&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ให้ Spring ฉีด dependency มาให้อัตโนมัติ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Value&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;อ่านค่าจาก &lt;code&gt;application.properties&lt;/code&gt; หรือ &lt;code&gt;yaml&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@RequestMapping&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;กำหนด path และ method ของ API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;@GetMapping&lt;/code&gt;, &lt;code&gt;@PostMapping&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;ตัวย่อของ &lt;code&gt;@RequestMapping(method = …)&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;@RequestBody&lt;/code&gt;, &lt;code&gt;@PathVariable&lt;/code&gt;, &lt;code&gt;@RequestParam&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;รับข้อมูลจาก HTTP request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Bean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;บอกว่า method นี้ return เป็น Spring bean&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🧩 ตัวอย่าง REST API Controller ด้วย Spring + Lombok&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
@RequiredArgsConstructor
@RequestMapping("/api/users")
public class UserController {

    private final UserService userService;

    @GetMapping("/{id}")
    public UserDto getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }

    @PostMapping
    public UserDto createUser(@RequestBody CreateUserRequest request) {
        return userService.createUser(request);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Data
public class CreateUserRequest {
    private String name;
    private int age;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📚 สรุปหัวข้อเสริม&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Lombok ช่วยลดโค้ดซ้ำซ้อน ทำให้ class สั้น กระชับ (Boilerplate code-โค้ดพื้นฐานที่ต้องเขียนซ้ำ ๆ เพื่อให้ระบบทำงาน แต่ไม่ใช่ logic หลัก) &lt;/li&gt;
&lt;li&gt;✅ ใช้ annotation เช่น &lt;a class="mentioned-user" href="https://dev.to/data"&gt;@data&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt;, @RequiredArgsConstructor บ่อยมากใน Spring&lt;/li&gt;
&lt;li&gt;✅ เข้าใจ annotation ของ Spring จะช่วยให้พัฒนาได้รวดเร็ว และอธิบายโค้ดได้เวลาสัมภาษณ์&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;คำถามสัมภาษณ์เกี่ยวกับ Lombok &amp;amp; Spring Annotations&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;คำถาม&lt;/th&gt;
&lt;th&gt;แนวคำตอบ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;@Data&lt;/code&gt; ต่างจาก &lt;code&gt;@Getter/@Setter&lt;/code&gt; อย่างไร?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@Data&lt;/code&gt; รวมหลาย annotation ในตัวเดียว เช่น &lt;code&gt;toString&lt;/code&gt;, &lt;code&gt;equals&lt;/code&gt;, &lt;code&gt;hashCode&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;@Autowired&lt;/code&gt; ทำงานอย่างไร?&lt;/td&gt;
&lt;td&gt;Spring จะ inject bean โดยอัตโนมัติตาม type หรือ name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;@Component&lt;/code&gt; ต่างจาก &lt;code&gt;@Service&lt;/code&gt; หรือ &lt;code&gt;@Repository&lt;/code&gt; ไหม?&lt;/td&gt;
&lt;td&gt;ทั้งหมดเป็น component เหมือนกัน แต่ใช้เพื่อจำแนก role ต่างกัน (best practice)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ Lombok แล้ว debug ยากไหม?&lt;/td&gt;
&lt;td&gt;อาจยากขึ้นถ้าไม่เข้าใจว่ามัน generate อะไรบ้าง ต้องดู bytecode หรือใช้ IDE ที่รองรับ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;คำถามสัมภาษณ์งานยอดนิยม&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;คำถาม&lt;/th&gt;
&lt;th&gt;ประเด็นที่ควรรู้&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Java กับ JavaScript เหมือนกันมั้ย?&lt;/td&gt;
&lt;td&gt;ไม่เหมือนกันเลย&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;final คืออะไร&lt;/td&gt;
&lt;td&gt;ใช้กับตัวแปร เมธอด หรือคลาส เพื่อไม่ให้เปลี่ยนแปลง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overloading vs Overriding&lt;/td&gt;
&lt;td&gt;Overload: ชื่อเดียว พารามิเตอร์ต่างกัน, Override: เขียนทับจาก superclass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;String กับ StringBuilder ต่างกันยังไง?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;String&lt;/code&gt; immutable, &lt;code&gt;StringBuilder&lt;/code&gt; mutable และเร็วกว่า&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JVM, JRE, JDK ต่างกันยังไง?&lt;/td&gt;
&lt;td&gt;JVM: รัน, JRE: รัน + ไลบรารี, JDK: ใช้เขียน + compile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spring Framework คืออะไร?&lt;/td&gt;
&lt;td&gt;Framework ช่วยพัฒนา Java Web Application โดยเน้น DI และ AOP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JDBC ทำงานอย่างไร?&lt;/td&gt;
&lt;td&gt;เชื่อมต่อฐานข้อมูลผ่าน API ที่มาตรฐานของ Java&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;REST API คืออะไร?&lt;/td&gt;
&lt;td&gt;สถาปัตยกรรมสำหรับการสื่อสารระหว่าง Client-Server ด้วย HTTP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>java</category>
      <category>springboot</category>
    </item>
    <item>
      <title>ติวสอบสัมภาษณ์งาน Java เบื้องต้น ฉบับ มือใหม่ [1]</title>
      <dc:creator>c_nooknook_daily_prompt</dc:creator>
      <pubDate>Wed, 25 Jun 2025 03:21:55 +0000</pubDate>
      <link>https://dev.to/nooknookwork/tiwsbsamphaasn-java-ebuuengtn-chbab-muueaihm-1-3m5d</link>
      <guid>https://dev.to/nooknookwork/tiwsbsamphaasn-java-ebuuengtn-chbab-muueaihm-1-3m5d</guid>
      <description>&lt;p&gt;&lt;strong&gt;Object-Oriented Programming&lt;/strong&gt; &lt;strong&gt;(การเขียนโปรแกรมเชิงวัตถุ)&lt;/strong&gt; คือ แนวคิดในการเขียนโปรแกรมที่เน้นการแบ่งระบบออกเป็น "วัตถุ" (Objects) โดยวัตถุแต่ละชิ้นจะเป็นตัวแทนของสิ่งของหรือแนวคิดในโลกจริง และมี "ข้อมูล" (Attributes) กับ "พฤติกรรม" (Methods) ของตัวเอง&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;สั้นๆ&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;"OOP คือแนวทางเขียนโปรแกรมโดยมอง "ปัญหา" เป็นกลุ่มของวัตถุที่สื่อสารกัน"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4 เสาหลักของ OOP ที่ต้องจำให้แม่น&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;🔢&lt;/th&gt;
&lt;th&gt;ชื่อหลักการ&lt;/th&gt;
&lt;th&gt;คำอธิบายแบบเข้าใจง่าย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1️⃣&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Encapsulation&lt;/strong&gt; (การห่อหุ้มข้อมูล)&lt;/td&gt;
&lt;td&gt;ซ่อนข้อมูลภายใน object ไม่ให้เข้าถึงโดยตรง ใช้ &lt;code&gt;private&lt;/code&gt; + &lt;code&gt;getter/setter&lt;/code&gt; เพื่อควบคุมการเข้าถึง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2️⃣&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Abstraction&lt;/strong&gt; (การย่อรายละเอียด)&lt;/td&gt;
&lt;td&gt;ซ่อนรายละเอียดการทำงานที่ซับซ้อนไว้เบื้องหลัง เผยเฉพาะสิ่งที่จำเป็น เช่น ผ่าน &lt;code&gt;abstract class&lt;/code&gt; หรือ &lt;code&gt;interface&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3️⃣&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Inheritance&lt;/strong&gt; (การสืบทอดคุณสมบัติ)&lt;/td&gt;
&lt;td&gt;ให้ class ใหม่สามารถ “รับมรดก” จาก class เดิมได้ ช่วยลดการเขียนโค้ดซ้ำ เช่น ใช้ &lt;code&gt;extends&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4️⃣&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Polymorphism&lt;/strong&gt; (ความหลากหลายของพฤติกรรม)&lt;/td&gt;
&lt;td&gt;object สามารถตอบสนองต่อ method เดียวกันได้หลายแบบ เช่น &lt;code&gt;overloading&lt;/code&gt; และ &lt;code&gt;overriding&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;"ห่อ ย่อ สืบ หลาย"&lt;/strong&gt;&lt;br&gt;
ห่อหุ้ม (Encapsulation) → ย่อรายละเอียด (Abstraction) → สืบทอด (Inheritance) → หลากหลายพฤติกรรม (Polymorphism)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;องค์ประกอบของ OOP&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Class (แม่แบบของวัตถุ) "พิมพ์เขียว" หรือ "สูตรการสร้างวัตถุ"&lt;/li&gt;
&lt;li&gt;Object (วัตถุจริงที่สร้างจาก class)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;OOP คือการเขียนโปรแกรมแบบมองโลกเป็นวัตถุ วัตถุแต่ละตัวมี ข้อมูลของตัวเอง และ สามารถกระทำบางอย่างได้ เหมาะกับโปรเจกต์ที่ซับซ้อนเพราะช่วย จัดระเบียบโค้ดให้เข้าใจง่ายและดูแลได้ดี&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Object-Oriented Programming (OOP)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Class &amp;amp; Object: พิมพ์เขียวและอินสแตนซ์&lt;/li&gt;
&lt;li&gt;Encapsulation: ซ่อนข้อมูล (ใช้ private + getter/setter)&lt;/li&gt;
&lt;li&gt;Inheritance: สืบทอดคุณสมบัติ (ใช้ extends)&lt;/li&gt;
&lt;li&gt;Polymorphism: เมธอดเดียว ใช้ได้หลายแบบ (Overloading / Overriding)&lt;/li&gt;
&lt;li&gt;Abstraction: ซ่อนรายละเอียดการทำงาน (ใช้ abstract class หรือ interface)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;องค์ประกอบหลักของ Class มีอะไรบ้าง?&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;องค์ประกอบ&lt;/th&gt;
&lt;th&gt;คำอธิบาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fields (Attributes / Properties)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ตัวแปรที่เก็บ "ข้อมูล" ของ object เช่น ชื่อ อายุ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Constructors&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;เมธอดพิเศษที่ใช้สร้าง object จาก class นั้น&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Methods (พฤติกรรม)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;เมธอดที่อธิบาย "สิ่งที่ object ทำได้"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Access Modifiers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;เช่น &lt;code&gt;public&lt;/code&gt;, &lt;code&gt;private&lt;/code&gt;, &lt;code&gt;protected&lt;/code&gt; – กำหนดการเข้าถึงองค์ประกอบใน class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Static Members&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ฟิลด์หรือเมธอดที่เป็นของ class ทั้งหมด ไม่ใช่เฉพาะ object ใด object หนึ่ง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Nested Classes (ถ้ามี)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;class ที่ประกาศซ้อนอยู่ภายใน class อื่น&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Annotations (ถ้ามี)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;เช่น &lt;code&gt;@Override&lt;/code&gt;, &lt;code&gt;@Getter&lt;/code&gt; ฯลฯ เพื่อกำหนดพฤติกรรมพิเศษ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Class = ข้อมูล + พฤติกรรม + วิธีสร้าง + การควบคุมการเข้าถึง&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Class = Field + Constructor + Method (+ Access Control)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Types (ชนิดข้อมูล) หลัก ๆ อยู่ 2 กลุ่มใหญ่&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Primitive Data Types (ชนิดข้อมูลพื้นฐาน)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Java มี 8 ชนิดที่เป็นข้อมูลดิบแบบเบา ไม่ใช่ object ใช้บ่อยมาก!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ชนิด&lt;/th&gt;
&lt;th&gt;ขนาด&lt;/th&gt;
&lt;th&gt;ตัวอย่าง&lt;/th&gt;
&lt;th&gt;คำอธิบาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;byte&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8-bit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;byte b = 127;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;เลขจำนวนเต็มขนาดเล็ก (-128 ถึง 127)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;short&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16-bit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;short s = 1000;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ตัวเลขขนาดกลาง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;32-bit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int age = 30;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;จำนวนเต็มทั่วไป&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;long&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;64-bit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;long population = 8000000000L;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ตัวเลขใหญ่&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;float&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;32-bit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;float pi = 3.14f;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ทศนิยมเบา ต้องลงท้ายด้วย &lt;code&gt;f&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;double&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;64-bit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;double d = 3.14159;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ทศนิยมละเอียด ใช้บ่อยกว่า float&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;char&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16-bit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;char c = 'A';&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ตัวอักษร 1 ตัว (ใช้ single quote &lt;code&gt;'&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1-bit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;boolean flag = true;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;มีแค่ &lt;code&gt;true&lt;/code&gt; หรือ &lt;code&gt;false&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Reference Data Types (ชนิดข้อมูลอ้างอิง)
คือข้อมูลที่ อ้างถึง object หรือคลาส เช่น:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ชนิด&lt;/th&gt;
&lt;th&gt;ตัวอย่าง&lt;/th&gt;
&lt;th&gt;คำอธิบาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;String&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"Hello"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ตัวอักษรหลายตัว (เป็น object)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Array&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int[] numbers = {1, 2, 3};&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;เก็บข้อมูลหลายค่าในตัวแปรเดียว&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Class&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Person p = new Person();&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;เก็บวัตถุที่เราสร้างจาก class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Interface&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Runnable r = () -&amp;gt; {}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ตัวแปรที่อ้างถึง interface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Map&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;จาก Java Collections&lt;/td&gt;
&lt;td&gt;เก็บข้อมูลหลายแบบในรูปโครงสร้างที่ยืดหยุ่น&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Primitive Types (8 แบบ):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;byte, short, int, long&lt;/li&gt;
&lt;li&gt;float, double&lt;/li&gt;
&lt;li&gt;char, boolean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Reference Types:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;String, Array, Object, Class, List, Map ฯลฯ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;การสร้างคลาส&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Person { // Class Declaration

    // Fields
    private String name;
    private int age;

    // Constructor
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Methods
    public void sayHello() {
        System.out.println("Hi, I'm " + name + " and I'm " + age + " years old.");
    }

    // Getter &amp;amp; Setter (Encapsulation)
    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    // Static Method
    public static void describeClass() {
        System.out.println("This is a Person class.");
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;สร้างวัตถุจากคลาส&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ชื่อคลาส ชื่อตัวแปร = new ชื่อคลาส(พารามิเตอร์);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Collections Framework&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Java Collections Framework คืออะไร?&lt;/strong&gt;&lt;br&gt;
Collections Framework คือชุดของ class และ interface ที่ Java เตรียมไว้ให้สำหรับจัดการ กลุ่มข้อมูล (Group of Objects) อย่างมีประสิทธิภาพ เช่น การเก็บข้อมูล, ค้นหา, เพิ่ม, ลบ, เรียงลำดับ ฯลฯ&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;หมวดหมู่หลักของ Collection (แบ่งตามโครงสร้าง)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java แบ่ง Collection ออกเป็น 3 กลุ่มหลักใหญ่ ๆ:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;กลุ่มหลัก&lt;/th&gt;
&lt;th&gt;Interface&lt;/th&gt;
&lt;th&gt;ตัวอย่างคลาสยอดนิยม&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;List&lt;/strong&gt; (ลำดับ)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;List&amp;lt;E&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ArrayList&lt;/code&gt;, &lt;code&gt;LinkedList&lt;/code&gt;, &lt;code&gt;Vector&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Set&lt;/strong&gt; (ไม่ซ้ำ)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Set&amp;lt;E&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;HashSet&lt;/code&gt;, &lt;code&gt;LinkedHashSet&lt;/code&gt;, &lt;code&gt;TreeSet&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Map&lt;/strong&gt; (คีย์-ค่า)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Map&amp;lt;K, V&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;HashMap&lt;/code&gt;, &lt;code&gt;LinkedHashMap&lt;/code&gt;, &lt;code&gt;TreeMap&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Queue / Deque&lt;/strong&gt; (คิว)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Queue&amp;lt;E&amp;gt;&lt;/code&gt;, &lt;code&gt;Deque&amp;lt;E&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;PriorityQueue&lt;/code&gt;, &lt;code&gt;ArrayDeque&lt;/code&gt;, &lt;code&gt;LinkedList&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;List (ลำดับข้อมูล, มี index)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เก็บข้อมูลแบบเรียงลำดับ&lt;/li&gt;
&lt;li&gt;มี index (เริ่มที่ 0)&lt;/li&gt;
&lt;li&gt;ซ้ำกันได้
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List&amp;lt;String&amp;gt; names = new ArrayList&amp;lt;&amp;gt;();
names.add("Alice");
names.add("Bob");
System.out.println(names.get(0)); // Alice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;คลาสที่ใช้บ่อย:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ArrayList – โครงสร้าง array, เข้าถึงเร็ว&lt;/li&gt;
&lt;li&gt;LinkedList – เพิ่ม/ลบไว (โดยเฉพาะกลางรายการ)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Set (ไม่มีข้อมูลซ้ำ)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ ไม่มี index&lt;/li&gt;
&lt;li&gt;❌ ไม่เก็บข้อมูลซ้ำ
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Set&amp;lt;String&amp;gt; ids = new HashSet&amp;lt;&amp;gt;();
ids.add("A001");
ids.add("A001"); // ซ้ำ → ไม่เก็บ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;สรุป Collections Framework แบบภาพรวม&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        Collection
           |
   ------------------
   |       |        |
 List     Set     Queue
           |
         SortedSet (TreeSet)

        Map
         |
     SortedMap (TreeMap)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;List → มีลำดับ ซ้ำได้&lt;/li&gt;
&lt;li&gt;Set → ไม่มีซ้ำ ไม่มี index&lt;/li&gt;
&lt;li&gt;Map → เก็บคู่ Key-Value&lt;/li&gt;
&lt;li&gt;Queue → เข้าก่อนออกก่อน (FIFO)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;สำหรับมือใหม่จะมีความสับสนระหว่าง &lt;code&gt;Array&lt;/code&gt; กับ &lt;code&gt;List&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Array กับ List ต่างกันชัดเจนทั้งในเรื่องโครงสร้าง ความยืดหยุ่น และวิธีใช้&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Array กับ List ต่างกันชัดเจนทั้งในเรื่องโครงสร้าง ความยืดหยุ่น และวิธีใช้&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔸 Array = โครงสร้างพื้นฐาน, ขนาดคงที่, ทำงานเร็ว&lt;br&gt;
🔹 List = เป็น interface ใน Collections Framework, ขยายได้, ใช้งานยืดหยุ่น&lt;/p&gt;

&lt;p&gt;❓ Array กับ List ต่างกันอย่างไร?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;จุดเปรียบเทียบ&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Array&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;List (เช่น ArrayList)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ประเภท&lt;/td&gt;
&lt;td&gt;โครงสร้างข้อมูลแบบพื้นฐาน (built-in)&lt;/td&gt;
&lt;td&gt;Interface + Class จาก Collections Framework&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ขนาด&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;คงที่&lt;/strong&gt; กำหนดตอนสร้างแล้วเปลี่ยนไม่ได้&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;ยืดหยุ่น&lt;/strong&gt; เพิ่ม/ลบได้ตามต้องการ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;การเข้าถึง&lt;/td&gt;
&lt;td&gt;เร็วมาก (index โดยตรง)&lt;/td&gt;
&lt;td&gt;เร็ว (แต่มี overhead จาก object management)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;การเพิ่ม/ลบข้อมูล&lt;/td&gt;
&lt;td&gt;เพิ่ม/ลบไม่ได้ ต้องสร้าง array ใหม่&lt;/td&gt;
&lt;td&gt;ทำได้สะดวก (&lt;code&gt;add&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ประเภทข้อมูล&lt;/td&gt;
&lt;td&gt;เก็บ primitive ได้ (เช่น &lt;code&gt;int[]&lt;/code&gt;) หรือ object&lt;/td&gt;
&lt;td&gt;เก็บ object (เช่น &lt;code&gt;List&amp;lt;Integer&amp;gt;&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;การใช้ memory&lt;/td&gt;
&lt;td&gt;ใช้ memory น้อยกว่า&lt;/td&gt;
&lt;td&gt;ใช้ memory มากกว่า เพราะเก็บ metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ฟังก์ชันเสริม&lt;/td&gt;
&lt;td&gt;ไม่มี method นอกจาก length&lt;/td&gt;
&lt;td&gt;มี method เช่น &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt;, &lt;code&gt;contains&lt;/code&gt;, &lt;code&gt;size&lt;/code&gt; ฯลฯ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;📊 เปรียบเทียบ Array กับ List แบบละเอียด&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;หัวข้อ&lt;/th&gt;
&lt;th&gt;&lt;code&gt;Array&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;List&lt;/code&gt; (&lt;code&gt;ArrayList&lt;/code&gt;, &lt;code&gt;LinkedList&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;คืออะไร?&lt;/td&gt;
&lt;td&gt;โครงสร้างข้อมูลพื้นฐาน&lt;/td&gt;
&lt;td&gt;Interface ใน Java Collections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ขนาด&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;คงที่&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;ยืดหยุ่น&lt;/strong&gt; (เพิ่ม/ลบได้)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Index&lt;/td&gt;
&lt;td&gt;มี&lt;/td&gt;
&lt;td&gt;มี&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;รองรับ Generic&lt;/td&gt;
&lt;td&gt;⛔ ไม่รองรับแบบสมบูรณ์&lt;/td&gt;
&lt;td&gt;✅ รองรับเต็มที่&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เพิ่ม/ลบข้อมูล&lt;/td&gt;
&lt;td&gt;ยุ่งยาก (ต้องสร้างใหม่)&lt;/td&gt;
&lt;td&gt;ง่าย (&lt;code&gt;add()&lt;/code&gt;, &lt;code&gt;remove()&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้งานจริง&lt;/td&gt;
&lt;td&gt;เบา เร็ว เหมาะกับข้อมูลไม่เปลี่ยน&lt;/td&gt;
&lt;td&gt;เหมาะกับโปรเจกต์จริง ใช้งานร่วมกับ Spring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ประสิทธิภาพ&lt;/td&gt;
&lt;td&gt;เร็วกว่าเล็กน้อย&lt;/td&gt;
&lt;td&gt;ช้ากว่าเล็กน้อย แต่ยืดหยุ่นกว่า&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ตัวอย่าง&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int[] arr = new int[3];&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;📌 Array&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int[] numbers = new int[3];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;

// ขนาดคงที่ เพิ่มใหม่ไม่ได้

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 List (ArrayList)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; numbers = new ArrayList&amp;lt;&amp;gt;();
numbers.add(10);
numbers.add(20);
numbers.add(30);
numbers.add(40); // เพิ่มได้ไม่จำกัด

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;strong&gt;เมื่อไรควรใช้?&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ใช้ &lt;strong&gt;Array&lt;/strong&gt;
&lt;/th&gt;
&lt;th&gt;ใช้ &lt;strong&gt;List&lt;/strong&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ข้อมูลคงที่ ไม่เพิ่ม/ลบบ่อย&lt;/td&gt;
&lt;td&gt;ต้องเพิ่ม ลบ ค้นหา บ่อย&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ต้องการประสิทธิภาพสูงสุด (speed/memory)&lt;/td&gt;
&lt;td&gt;ต้องการความสะดวกในการจัดการข้อมูล&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เก็บ primitive โดยตรง (เช่น &lt;code&gt;int[]&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;เก็บ object และใช้ method ที่ Collections Framework ให้มา&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;✅ &lt;strong&gt;สรุปจำง่าย&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📌 Array = เร็ว คงที่&lt;/li&gt;
&lt;li&gt;📌 List = ยืดหยุ่น ใช้ง่าย ใช้บ่อยใน Java สมัยใหม่&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔁 &lt;strong&gt;ถ้าเขียนโค้ด Java ยุคใหม่ หรือใช้ Spring Boot → ใช้ List เป็นหลัก&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;** วิธีแปลง Array ↔ List ใน Java**&lt;/p&gt;

&lt;p&gt;แปลง Array → List&lt;br&gt;
✅ แบบง่าย (ใช้ Arrays.asList)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;String[] arr = {"A", "B", "C"};
List&amp;lt;String&amp;gt; list = Arrays.asList(arr);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ หมายเหตุ: Arrays.asList() คืนค่าเป็น fixed-size list → เพิ่ม/ลบไม่ได้ (add() จะ error)&lt;/p&gt;

&lt;p&gt;✅ แบบยืดหยุ่น (แนะนำ)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List&amp;lt;String&amp;gt; list = new ArrayList&amp;lt;&amp;gt;(Arrays.asList(arr)); // สามารถ add/remove ได้
list.add("D"); // ✅ ทำได้

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spring Bean คือ อ็อบเจ็กต์ (Object) ที่ถูกจัดการโดย Spring IoC Container (Inversion of Control) ในเฟรมเวิร์ก Spring. พูดง่ายๆ คือ Spring Bean คือ Java Object ที่ Spring Framework สร้าง, จัดการ, และกำหนดค่าให้. คอนเทนเนอร์ Spring IoC จะรับผิดชอบในการสร้าง, จัดการ, และทำลาย Bean เหล่านี้&lt;/p&gt;

&lt;p&gt;Inversion of control เป็น concept รูปแบบนึงที่ช่วยลดความผูกมัดกันระหว่าง module หรือ object เพื่อช่วยให้ code ของเรา clean, maintain ง่าย และ test ง่าย ซึ่งตัว IoC นั้นมีวิธีการ implement หลายแบบ แต่วันนี้เราจะมาพูดถึง Dependency Injection &lt;/p&gt;

&lt;p&gt;Dependency Injection เป็นรูปแบบการ implement แบบนึงของ IoC โดยการ inject object ผ่าน constructor&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>java</category>
      <category>oop</category>
    </item>
    <item>
      <title>useReducer , Redux, Redux Toolkit (RTK)</title>
      <dc:creator>c_nooknook_daily_prompt</dc:creator>
      <pubDate>Tue, 24 Jun 2025 01:50:53 +0000</pubDate>
      <link>https://dev.to/nooknookwork/usereducer-redux-redux-toolkit-rtk-c66</link>
      <guid>https://dev.to/nooknookwork/usereducer-redux-redux-toolkit-rtk-c66</guid>
      <description>&lt;p&gt;&lt;strong&gt;useReducer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;useReducer คือ Hook ที่ใช้จัดการ state แบบที่มี หลายสถานะ หรือ logic ซับซ้อน&lt;br&gt;
คล้าย Redux ย่อส่วน ใช้คู่กับ dispatch และ reducer function&lt;/p&gt;

&lt;p&gt;ตัวอย่างง่าย ๆ: Counter&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useReducer } from 'react';

function counterReducer(state: number, action: { type: string }) {
  switch (action.type) {
    case 'increment':
      return state + 1;
    case 'decrement':
      return state - 1;
    default:
      return state;
  }
}

export default function Counter() {
  const [count, dispatch] = useReducer(counterReducer, 0);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;Count: {count}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch({ type: 'increment' })}&amp;gt;เพิ่ม&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch({ type: 'decrement' })}&amp;gt;ลด&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;โครงสร้างจำง่าย:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [state, dispatch] = useReducer(reducerFunction, initialState);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;state → ค่าปัจจุบัน&lt;/li&gt;
&lt;li&gt;dispatch(action) → ส่ง action ไปให้ reducer&lt;/li&gt;
&lt;li&gt;reducer(state, action) → ฟังก์ชันที่กำหนดว่า state จะเปลี่ยนยังไง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ใช้เมื่อไหร่ดี?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ต้องจัดการ state ที่มีหลายประเภท เช่น เพิ่ม, ลบ, รีเซ็ต&lt;/li&gt;
&lt;li&gt;ต้องการแยก logic ออกจาก component (เช่น form, cart, etc.)&lt;/li&gt;
&lt;li&gt;ไม่อยากใช้ Redux แต่ logic คล้ายกัน&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ประกาศประเภท State และ Action&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type State = {
  count: number;
  showCount: boolean;
};

type Action =
  | { type: 'increment' }
  | { type: 'decrement' }
  | { type: 'reset' }
  | { type: 'toggle' };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เขียน reducer ฟังก์ชัน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + 1 };
    case 'decrement':
      return { ...state, count: state.count - 1 };
    case 'reset':
      return { ...state, count: 0 };
    case 'toggle':
      return { ...state, showCount: !state.showCount };
    default:
      return state;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใช้งานในคอมโพเนนต์&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useReducer } from 'react';

const initialState: State = {
  count: 0,
  showCount: true,
};

export default function CounterReducer() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h2&amp;gt;useReducer แบบ Object State + TypeScript&amp;lt;/h2&amp;gt;

      &amp;lt;button onClick={() =&amp;gt; dispatch({ type: 'toggle' })}&amp;gt;
        {state.showCount ? 'ซ่อน' : 'แสดง'} ตัวเลข
      &amp;lt;/button&amp;gt;

      {state.showCount &amp;amp;&amp;amp; &amp;lt;p&amp;gt;Count: {state.count}&amp;lt;/p&amp;gt;}

      &amp;lt;button onClick={() =&amp;gt; dispatch({ type: 'increment' })}&amp;gt;เพิ่ม&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch({ type: 'decrement' })}&amp;gt;ลด&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch({ type: 'reset' })}&amp;gt;รีเซ็ต&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;สรุปจำง่าย&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ส่วนประกอบ&lt;/th&gt;
&lt;th&gt;ทำหน้าที่อะไร&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;State&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;โครงสร้างข้อมูลที่เราจะเก็บ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Action&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ชนิดของคำสั่งที่ส่งเข้า reducer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reducer()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ฟังก์ชันหลักที่กำหนดว่า state เปลี่ยนยังไง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dispatch()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ใช้ส่ง action เข้า reducer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Redux&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Redux แบบดั้งเดิม (Vanilla Redux) เพื่อความเข้าใจ หลักการพื้นฐานจริง ๆ ก่อนใช้ Redux Toolkit&lt;br&gt;
เราจะมาเริ่มจากโค้ดพื้นฐานที่ใช้แนวคิด action → reducer → store → dispatch ค่ะ&lt;/p&gt;

&lt;p&gt;ติดตั้ง redux และ react-redux&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install redux react-redux

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สร้าง Action Type และ Action Creator&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// action types
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const RESET = 'RESET';

// action creators
export const increment = () =&amp;gt; ({ type: INCREMENT });
export const decrement = () =&amp;gt; ({ type: DECREMENT });
export const reset = () =&amp;gt; ({ type: RESET });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สร้าง Reducer&lt;/p&gt;

&lt;p&gt;src/redux/reducer.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { INCREMENT, DECREMENT, RESET } from './actions';

const initialState = {
  count: 0,
};

export const counterReducer = (state = initialState, action) =&amp;gt; {
  switch (action.type) {
    case INCREMENT:
      return { ...state, count: state.count + 1 };
    case DECREMENT:
      return { ...state, count: state.count - 1 };
    case RESET:
      return { ...state, count: 0 };
    default:
      return state;
  }
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สร้าง Store&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createStore } from 'redux';
import { counterReducer } from './reducer';

export const store = createStore(counterReducer);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ครอบ  ด้วย &lt;/p&gt;

&lt;p&gt;src/main.jsx (หรือ index.js)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { store } from './redux/store';

ReactDOM.createRoot(document.getElementById('root')).render(
  &amp;lt;Provider store={store}&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/Provider&amp;gt;
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใช้ใน Component&lt;/p&gt;

&lt;p&gt;src/App.jsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, reset } from './redux/actions';

export default function App() {
  const count = useSelector(state =&amp;gt; state.count);
  const dispatch = useDispatch();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Counter: {count}&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch(increment())}&amp;gt;เพิ่ม&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch(decrement())}&amp;gt;ลด&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch(reset())}&amp;gt;รีเซ็ต&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;สรุปโครงสร้าง Redux ดั้งเดิม&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ส่วนประกอบ&lt;/th&gt;
&lt;th&gt;หน้าที่&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;action&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;สิ่งที่บอกว่า "จะทำอะไร" (type: 'INCREMENT')&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reducer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;รับ state + action → คืนค่า state ใหม่&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;store&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ที่รวม state และจัดการ dispatch, subscribe ฯลฯ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dispatch()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ส่ง action ไปให้ reducer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Provider&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ครอบแอปเพื่อให้ทุก component ใช้ store ได้&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;useSelector()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ดึงค่า state จาก store&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;useDispatch()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ส่ง action เข้าสู่ store&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Redux Toolkit (RTK)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;เริ่มต้นใช้ Redux ง่าย ๆ แนะนำให้เริ่มจาก Redux Toolkit (RTK) ซึ่งเป็นวิธีที่ทีม Redux แนะนำให้ใช้เป็นหลักในปัจจุบัน เพราะลดความซับซ้อนและโค้ดเยอะจาก Redux แบบดั้งเดิม&lt;/p&gt;

&lt;p&gt;เป้าหมาย: "สร้าง Counter App ด้วย Redux Toolkit"&lt;/p&gt;

&lt;p&gt;ขั้นตอนง่าย ๆ (แบบ Step-by-Step)&lt;/p&gt;

&lt;p&gt;ติดตั้ง Redux Toolkit + React Redux&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @reduxjs/toolkit react-redux

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สร้าง store&lt;/p&gt;

&lt;p&gt;src/store.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

// สำหรับใช้ใน TypeScript
export type RootState = ReturnType&amp;lt;typeof store.getState&amp;gt;;
export type AppDispatch = typeof store.dispatch;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สร้าง slice&lt;/p&gt;

&lt;p&gt;src/counterSlice.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
  },
  reducers: {
    increment: (state) =&amp;gt; {
      state.value += 1;
    },
    decrement: (state) =&amp;gt; {
      state.value -= 1;
    },
    reset: (state) =&amp;gt; {
      state.value = 0;
    },
  },
});

export const { increment, decrement, reset } = counterSlice.actions;
export default counterSlice.reducer;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ครอบแอปด้วย Provider&lt;/p&gt;

&lt;p&gt;src/main.tsx หรือ src/index.tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { store } from './store';

ReactDOM.createRoot(document.getElementById('root')!).render(
  &amp;lt;Provider store={store}&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/Provider&amp;gt;
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใช้ใน Component&lt;/p&gt;

&lt;p&gt;src/App.tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useSelector, useDispatch } from 'react-redux';
import { RootState, AppDispatch } from './store';
import { increment, decrement, reset } from './counterSlice';

export default function App() {
  const count = useSelector((state: RootState) =&amp;gt; state.counter.value);
  const dispatch: AppDispatch = useDispatch();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;นับเลข: {count}&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch(increment())}&amp;gt;เพิ่ม&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch(decrement())}&amp;gt;ลด&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch(reset())}&amp;gt;รีเซ็ต&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สรุปจำง่าย&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;สิ่งที่ทำ&lt;/th&gt;
&lt;th&gt;ชื่อไฟล์&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;สร้าง state + action&lt;/td&gt;
&lt;td&gt;&lt;code&gt;counterSlice.ts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;รวม reducer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;store.ts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ครอบ &lt;code&gt;Provider&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;main.tsx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้งานในหน้า UI&lt;/td&gt;
&lt;td&gt;&lt;code&gt;App.tsx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;เคล็ดลับ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RTK ใช้ Immer อยู่แล้ว → สามารถ "แก้ state ตรง ๆ" ได้&lt;/li&gt;
&lt;li&gt;ใช้ useSelector() เพื่ออ่านค่า&lt;/li&gt;
&lt;li&gt;ใช้ useDispatch() เพื่อเรียก action ไปเปลี่ยนค่า&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>เจาะลึกเหตุผลที่ JSX ใช้ onClick แบบ camelCase</title>
      <dc:creator>c_nooknook_daily_prompt</dc:creator>
      <pubDate>Mon, 23 Jun 2025 09:08:11 +0000</pubDate>
      <link>https://dev.to/nooknookwork/ecchaaaluekehtuphlthii-jsx-aich-onclick-aebb-camelcase-17p3</link>
      <guid>https://dev.to/nooknookwork/ecchaaaluekehtuphlthii-jsx-aich-onclick-aebb-camelcase-17p3</guid>
      <description>&lt;p&gt;&lt;strong&gt;คำว่า onClick (ตัว C ใหญ่) ที่เราใช้ใน JSX ไม่ได้เป็นแค่ "ตัวสะกดแปลก ๆ" แต่มีความเกี่ยวข้องลึกกับ JavaScript, JSX, DOM, และ React&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ทำไมใน JSX เขียน onClick ไม่ใช่ onclick?&lt;/p&gt;

&lt;p&gt;เพราะใน JSX เรากำลังเขียน JavaScript object syntax ที่ map ไปยัง DOM properties ไม่ใช่ HTML attributes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;อธิบายแบบเข้าใจง่ายๆก็คือ&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HTML ใช้ attribute → lowercase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;onclick = attribute ที่ browser อ่านได้จาก HTML
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- HTML ธรรมดา --&amp;gt;
&amp;lt;button onclick="alert('hi')"&amp;gt;Click&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JSX ไม่ใช่ HTML → เป็น JavaScript&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;onClick = property ของ JavaScript object
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button onClick={() =&amp;gt; alert("hi")}&amp;gt;Click&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React จะเอาค่าใน JSX ไปแปลงเป็น JavaScript เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React.createElement("button", {
  onClick: () =&amp;gt; alert("hi")
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ที่สำคัญ: ใน DOM จริง ๆ onClick คือ property ของ DOM element (HTMLElement.prototype.onclick)&lt;/p&gt;

&lt;p&gt;ชื่อ property ใน JavaScript = camelCase&lt;/p&gt;

&lt;p&gt;ดังนั้น...&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;มุมมอง&lt;/th&gt;
&lt;th&gt;ใช้แบบไหน&lt;/th&gt;
&lt;th&gt;เพราะอะไร&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HTML (แท้ ๆ)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;onclick&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;เป็น HTML attribute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSX (React)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;onClick&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;เป็น JavaScript property (camelCase)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;เกี่ยวข้องกับ object key ไหม?&lt;/p&gt;

&lt;p&gt;เกี่ยว! เพราะ JSX จะถูกแปลงเป็น JavaScript object&lt;br&gt;
และ key ของ object (เช่น onClick) ต้องเขียนให้ตรงกับ property ชื่อจริงใน DOM API&lt;br&gt;
ซึ่งเป็น camelCase ตาม JavaScript convention&lt;/p&gt;

&lt;p&gt;ตัวอย่าง JSX → JS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="text" onChange={handleChange} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;--&amp;gt; จะกลายเป็น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React.createElement("input", {
  type: "text",
  onChange: handleChange
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;สรุป&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;onClick = React ใช้ JavaScript syntax → ต้อง camelCase&lt;/li&gt;
&lt;li&gt;JSX ไม่ใช่ HTML → React จึงไม่ใช้ onclick แบบ HTML&lt;/li&gt;
&lt;li&gt;เกี่ยวข้องกับ object key เพราะ JSX = การส่ง props เป็น object&lt;/li&gt;
&lt;li&gt;React จะ map key เช่น onClick ไปยัง DOM property element.onclick = ...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmn7xv315rrf485sdlhlj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmn7xv315rrf485sdlhlj.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;โบนัส&lt;/strong&gt;&lt;br&gt;
การที่เราใช้ { สองครั้งใน JSX ของ React เพื่อกำหนด style นั้น เกี่ยวข้องกับการส่ง JavaScript object เข้าไป ใน props ของ JSX โดยตรง ซึ่งเรามาอธิบายกันแบบเข้าใจง่ายๆ:&lt;/p&gt;

&lt;p&gt;🔍 โครงสร้างของ style ใน JSX&lt;br&gt;
เมื่อเราเขียน JSX แบบนี้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div style={{ color: 'red' }}&amp;gt;Hello&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;มันมี { สองระดับเพราะว่า:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ชั้นนอก { ... }: เป็นการบอก React ว่า “ค่าที่อยู่ภายในนี้เป็น JavaScript expression” ไม่ใช่ string ธรรมดา&lt;/li&gt;
&lt;li&gt;ชั้นใน { color: 'red' }: คือ JavaScript object ที่ใช้แทน CSS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔁 เปรียบเทียบกับ HTML ปกติ&lt;br&gt;
ใน HTML ปกติ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div style="color: red;"&amp;gt;Hello&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;style คือ string&lt;/p&gt;

&lt;p&gt;แต่ใน React JSX เราไม่ใช้ string — เราใช้ object แทน เพราะ React ต้องการให้ style ถูกจัดการเป็น JavaScript object&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;ตัวอย่างเพิ่มเติม&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const myStyle = {
  backgroundColor: 'blue',
  fontSize: '20px'
};

function MyComponent() {
  return &amp;lt;div style={myStyle}&amp;gt;Styled div&amp;lt;/div&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หรือแบบ inline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div style={{ backgroundColor: 'yellow', padding: '10px' }}&amp;gt;Nice!&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚫 &lt;strong&gt;ถ้าใช้ { ครั้งเดียวจะเกิดอะไร?&lt;/strong&gt;&lt;br&gt;
ถ้าเขียนแบบนี้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div style={ color: 'red' }&amp;gt;Hello&amp;lt;/div&amp;gt; // ❌ Error!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จะได้ error เพราะ React จะไม่เข้าใจว่า color: 'red' คืออะไร — ต้องห่อมันใน object ก่อน&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;ความหมาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{ ... }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JSX expression (JS code)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{ key: value }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JavaScript object (CSS แบบ object)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ดังนั้น style={{ color: 'red' }} → ชั้นนอกคือ JSX expression, ชั้นในคือ CSS object ครับ&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>รู้หรือไม่ Next.js ใช้ SWC ด้วยนะ!</title>
      <dc:creator>c_nooknook_daily_prompt</dc:creator>
      <pubDate>Mon, 23 Jun 2025 07:06:16 +0000</pubDate>
      <link>https://dev.to/nooknookwork/ruuhruueaim-nextjs-aich-swc-dwyna-52i2</link>
      <guid>https://dev.to/nooknookwork/ruuhruueaim-nextjs-aich-swc-dwyna-52i2</guid>
      <description>&lt;p&gt;&lt;strong&gt;ตั้งแต่ Next.js v12 เป็นต้นมา&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Next.js ใช้ SWC (Rust-based compiler) แทน Babel เป็นค่าเริ่มต้น&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;เพราะ:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เร็วกว่า ~17x&lt;/li&gt;
&lt;li&gt;ใช้ memory น้อย&lt;/li&gt;
&lt;li&gt;แปล JSX/TS ได้เหมือน Babel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;แต่ถ้าคุณสร้าง babel.config.js ➤ Next.js จะ fallback ไปใช้ Babel แทนทันทีค่ะ&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ref: &lt;a href="https://nextjs.org/docs/architecture/nextjs-compiler" rel="noopener noreferrer"&gt;nextjs-compiler&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;คำถาม&lt;/th&gt;
&lt;th&gt;คำตอบ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;❓ Babel ใน Next.js คืออะไร&lt;/td&gt;
&lt;td&gt;Compiler ที่แปลง JSX, TS, JS ใหม่ให้ browser เข้าใจ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❓ ต้องตั้งค่าไหม&lt;/td&gt;
&lt;td&gt;ไม่จำเป็น ถ้าใช้ config ปกติ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❓ จะใช้ Babel หรือ SWC?&lt;/td&gt;
&lt;td&gt;Next.js ใช้ SWC เป็น default, แต่คุณเปลี่ยนได้&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❓ ลองแปลงได้ที่ไหน&lt;/td&gt;
&lt;td&gt;&lt;a href="https://babeljs.io/repl" rel="noopener noreferrer"&gt;Babel REPL&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;คำแนะนำเมื่อใช้ Next.js:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ถ้าคุณ...&lt;/th&gt;
&lt;th&gt;แนะนำ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ JSX / TS ปกติ&lt;/td&gt;
&lt;td&gt;ไม่ต้องยุ่งกับ Babel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ต้องใช้ decorator / styled-components&lt;/td&gt;
&lt;td&gt;ค่อยเพิ่ม &lt;code&gt;babel.config.js&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;อยาก build ให้เบาที่สุด&lt;/td&gt;
&lt;td&gt;ปรับ Babel config, หรือใช้ SWC (Next.js รองรับแล้ว)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;✅ &lt;strong&gt;สถานการณ์ที่คุณ ควรปรับแต่ง Babel (ใช้ babel.config.js)&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;กรณี&lt;/th&gt;
&lt;th&gt;ทำไมต้องปรับ Babel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🔧 ใช้ &lt;strong&gt;decorators&lt;/strong&gt; (เช่นใน MobX, class-validator)&lt;/td&gt;
&lt;td&gt;ยังไม่ stable ใน JS ปกติ ต้องเปิด plugin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🎨 ใช้ &lt;strong&gt;styled-components&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;ต้องเปิด Babel plugin เพื่อให้ SSR + className ทำงานดีขึ้น&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📊 ใช้ library ที่ต้องการ plugin พิเศษ (เช่น lodash, react-intl)&lt;/td&gt;
&lt;td&gt;ปรับลดขนาด bundle หรือเพิ่ม optimization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;💬 ต้องการแปล message จาก code โดยตรง (i18n extract)&lt;/td&gt;
&lt;td&gt;ใช้ &lt;code&gt;babel-plugin-react-intl&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🚫 ต้องการ exclude หรือ include Babel เฉพาะบางไฟล์&lt;/td&gt;
&lt;td&gt;ปรับ rules แบบละเอียด&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;💥 ต้องรองรับ legacy browser พิเศษ (เช่น IE11)&lt;/td&gt;
&lt;td&gt;ปรับ preset-env target เอง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚙️ ต้องการ custom JSX runtime (แทน React)&lt;/td&gt;
&lt;td&gt;ปรับ JSX transform เอง เช่นใช้ preact หรือ emotion&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🛠 &lt;strong&gt;ตัวอย่าง Babel Plugin ที่ใช้บ่อย:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plugin&lt;/th&gt;
&lt;th&gt;ใช้ทำอะไร&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@babel/plugin-proposal-decorators&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;เปิดใช้ &lt;code&gt;@decorator&lt;/code&gt; บน class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;babel-plugin-styled-components&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ปรับปรุง SSR, ลด className ซ้ำซ้อน&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;babel-plugin-lodash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ลดขนาด bundle เวลาใช้ lodash&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;babel-plugin-import&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ทำ tree-shaking อัตโนมัติกับ lib เช่น antd&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@babel/plugin-proposal-class-properties&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;รองรับ field ใน class (เช่น &lt;code&gt;count = 0&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;📁 &lt;strong&gt;ตัวอย่างไฟล์ babel.config.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  presets: ['next/babel'], // ใช้ร่วมกับ Next.js
  plugins: [
    ['styled-components', { ssr: true }],
    ['@babel/plugin-proposal-decorators', { legacy: true }],
    ['@babel/plugin-proposal-class-properties', { loose: true }]
  ]
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;กรณี&lt;/th&gt;
&lt;th&gt;ทำไมไม่ต้อง&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ React, JSX, TypeScript ปกติ&lt;/td&gt;
&lt;td&gt;Next.js / CRA / Vite รองรับอยู่แล้ว&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ไม่ใช้ decorators หรือ styled-components&lt;/td&gt;
&lt;td&gt;ไม่ต้องเพิ่ม plugin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ไม่มีการ target browser พิเศษ&lt;/td&gt;
&lt;td&gt;preset-default เพียงพอ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🧠 &lt;strong&gt;เมื่อไหร่ “ไม่จำเป็น” ต้องปรับ Babel&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;กรณี&lt;/th&gt;
&lt;th&gt;ทำไมไม่ต้อง&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ React, JSX, TypeScript ปกติ&lt;/td&gt;
&lt;td&gt;Next.js / CRA / Vite รองรับอยู่แล้ว&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ไม่ใช้ decorators หรือ styled-components&lt;/td&gt;
&lt;td&gt;ไม่ต้องเพิ่ม plugin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ไม่มีการ target browser พิเศษ&lt;/td&gt;
&lt;td&gt;preset-default เพียงพอ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ lib ที่ต้องการ plugin&lt;/td&gt;
&lt;td&gt;styled-components, react-intl&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ต้องใช้ syntax ใหม่ (เช่น decorators)&lt;/td&gt;
&lt;td&gt;mobx, class-validator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ต้องปรับขนาด bundle&lt;/td&gt;
&lt;td&gt;tree-shaking, import แบบเฉพาะ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ต้องปรับ target browser&lt;/td&gt;
&lt;td&gt;IE11, low-spec device&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;✅ &lt;strong&gt;SWC คืออะไร?&lt;/strong&gt;&lt;br&gt;
SWC ย่อมาจาก Speedy Web Compiler&lt;br&gt;
คือ คอมไพเลอร์ (compiler) ที่เขียนด้วยภาษา Rust&lt;br&gt;
ใช้แปลงโค้ด JavaScript, TypeScript และ JSX เช่นเดียวกับ Babel แต่เร็วกว่า หลายเท่า&lt;/p&gt;

&lt;p&gt;🔧 &lt;strong&gt;SWC ทำอะไรได้เหมือน Babel ไหม?&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ทำอะไรได้บ้าง&lt;/th&gt;
&lt;th&gt;เหมือนกับ Babel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;แปลง JSX → JS&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;แปลง TypeScript → JS&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;รองรับ modern JS syntax (ES6+)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ทำ Tree Shaking&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;มี Plugin system (ยังจำกัด)&lt;/td&gt;
&lt;td&gt;🔶 ยังไม่ flexible เท่า Babel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;⚡ &lt;strong&gt;เปรียบเทียบ: SWC vs Babel&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ด้าน&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;SWC&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Babel&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ภาษา&lt;/td&gt;
&lt;td&gt;Rust (compiled)&lt;/td&gt;
&lt;td&gt;JavaScript (interpreter)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ความเร็ว&lt;/td&gt;
&lt;td&gt;🔥 เร็วกว่ามาก (~10–20x)&lt;/td&gt;
&lt;td&gt;ช้ากว่า (โดยเฉพาะไฟล์ใหญ่)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;รองรับ JSX / TS&lt;/td&gt;
&lt;td&gt;✅ เต็มรูปแบบ&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;รองรับ Plugins&lt;/td&gt;
&lt;td&gt;🔶 ยังไม่ครอบคลุมเท่า&lt;/td&gt;
&lt;td&gt;✅ ใช้ได้หลากหลาย&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ใน...&lt;/td&gt;
&lt;td&gt;Next.js, Vite, Turbopack&lt;/td&gt;
&lt;td&gt;Next.js (fallback), CRA, Webpack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customization ลึก&lt;/td&gt;
&lt;td&gt;🔽 ยังจำกัด&lt;/td&gt;
&lt;td&gt;✅ สูงมาก&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;📊 &lt;strong&gt;Benchmark (โดยทีม Vercel): SWC build เร็วกว่า Babel ถึง ~20 เท่า ในบางกรณี ใช้ memory น้อยกว่า&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ใช้ SWC ดีกว่า Babel ไหม?&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ถ้าคุณ...&lt;/th&gt;
&lt;th&gt;คำแนะนำ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;❌ ไม่ได้ใช้ Babel plugin พิเศษ&lt;/td&gt;
&lt;td&gt;✅ ใช้ SWC ไปเลย&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ ใช้ styled-components, decorator&lt;/td&gt;
&lt;td&gt;อาจต้องใช้ Babel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ต้องการ build ไว, ลดเวลา dev&lt;/td&gt;
&lt;td&gt;✅ SWC เหมาะมาก&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ต้องใช้ plugin/custom transform เฉพาะทาง&lt;/td&gt;
&lt;td&gt;➤ Babel ยังยืดหยุ่นกว่า&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;สรุป&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;คำถาม&lt;/th&gt;
&lt;th&gt;คำตอบ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;❓ SWC คืออะไร&lt;/td&gt;
&lt;td&gt;Compiler เขียนด้วย Rust สำหรับแปลง JS/TS/JSX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❓ ต่างจาก Babel ยังไง&lt;/td&gt;
&lt;td&gt;เร็วกว่า, ใช้ memory น้อย, แต่ plugin ยังไม่เยอะเท่า&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❓ ใช้กับอะไรได้บ้าง&lt;/td&gt;
&lt;td&gt;React, Next.js, Vite, รวมถึงการ build ทั่วไป&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❓ Next.js ใช้ไหม&lt;/td&gt;
&lt;td&gt;✅ ใช้ SWC เป็น default (เว้นแต่คุณใส่ babel.config.js)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;ตัวอย่าง Plugins ที่ Babel รองรับแต่ SWC ยังไม่รองรับ (หรือรองรับแค่บางส่วน)&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plugin&lt;/th&gt;
&lt;th&gt;ใช้ทำอะไร&lt;/th&gt;
&lt;th&gt;สถานะใน Babel&lt;/th&gt;
&lt;th&gt;สถานะใน SWC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@babel/plugin-proposal-decorators&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ใช้ &lt;code&gt;@decorator&lt;/code&gt; บน class (เช่น MobX, class-validator)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ ยังไม่รองรับ (กำลังพัฒนา)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;babel-plugin-styled-components&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ช่วยกับ SSR, ปรับ className styled-components&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ ยังไม่รองรับ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;babel-plugin-import&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Import แบบอัจฉริยะ (เช่น &lt;code&gt;antd&lt;/code&gt;, &lt;code&gt;lodash&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ ยัง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;babel-plugin-react-intl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ดึงข้อความเพื่อทำ i18n จาก JSX&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ ยังไม่รองรับ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;babel-plugin-transform-remove-console&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ลบ &lt;code&gt;console.log&lt;/code&gt; อัตโนมัติ&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ SWC ต้องใช้ custom transform หรือยังไม่ทำได้&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;babel-plugin-macros&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ใช้กับ &lt;code&gt;linaria&lt;/code&gt;, &lt;code&gt;emotion&lt;/code&gt;, &lt;code&gt;tailwind&lt;/code&gt; macros&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ ยัง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;babel-plugin-module-resolver&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ตั้ง alias import แบบ custom&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🔶 SWC รองรับแบบจำกัดใน config (&lt;code&gt;paths&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;⚠️ &lt;strong&gt;สรุปข้อจำกัดของ SWC (กลางปี 2025)&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ข้อจำกัด&lt;/th&gt;
&lt;th&gt;คำอธิบาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;❌ ยังไม่รองรับ Babel plugin ecosystem&lt;/td&gt;
&lt;td&gt;เช่น styled-components, decorators&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❌ ยังไม่รองรับ macro system เช่น &lt;code&gt;babel-plugin-macros&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;ใช้กับ emotion, tailwind, linaria&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔧 ต้องใช้ Rust custom plugin (ซับซ้อนกว่า Babel)&lt;/td&gt;
&lt;td&gt;ไม่สามารถเขียน JS plugin ง่าย ๆ ได้เหมือน Babel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚠️ ขาดบาง syntax proposal&lt;/td&gt;
&lt;td&gt;Decorators, pipeline, partial application เป็นต้น&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;✅ &lt;strong&gt;แล้วเมื่อไรควรใช้ Babel แทน SWC?&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;กรณี&lt;/th&gt;
&lt;th&gt;ใช้ Babel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ &lt;code&gt;@decorators&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ &lt;code&gt;styled-components&lt;/code&gt; SSR mode&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ import optimization (&lt;code&gt;babel-plugin-import&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ macro (tailwind macros, emotion macros)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ต้องเขียน plugin เองด้วย JS&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;✅ &lt;strong&gt;ใช้ SWC ได้เลย เมื่อ...&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;กรณี&lt;/th&gt;
&lt;th&gt;เหมาะกับ SWC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ React + TypeScript ธรรมดา&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ไม่ใช้ plugin พิเศษ&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;อยาก build เร็วมาก&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้ Next.js / Vite และไม่ใช้ &lt;code&gt;babel.config.js&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🔧 &lt;strong&gt;ทางเลือกบางส่วนใน SWC&lt;/strong&gt;&lt;br&gt;
ถ้าอยากใช้ styled-components กับ SWC ➤ ใช้ Emotion แทน (SWC รองรับ JSX pragma)&lt;br&gt;
หากอยากลบ console.log ➤ ทำผ่าน build tool เช่น esbuild plugin หรือ manual&lt;br&gt;
ถ้าอยากใช้ alias ➤ SWC รองรับ paths ใน tsconfig.json&lt;/p&gt;

&lt;p&gt;✨ &lt;strong&gt;สรุป&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;เปรียบเทียบ&lt;/th&gt;
&lt;th&gt;Babel&lt;/th&gt;
&lt;th&gt;SWC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Plugin ecosystem&lt;/td&gt;
&lt;td&gt;✅ ครอบคลุม&lt;/td&gt;
&lt;td&gt;❌ ยังไม่เต็ม&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ความเร็ว&lt;/td&gt;
&lt;td&gt;ช้ากว่า&lt;/td&gt;
&lt;td&gt;✅ เร็วกว่ามาก&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customization&lt;/td&gt;
&lt;td&gt;✅ เขียน plugin JS ได้เลย&lt;/td&gt;
&lt;td&gt;❌ ต้องเขียน Rust&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้กับ Next.js&lt;/td&gt;
&lt;td&gt;✅ fallback mode&lt;/td&gt;
&lt;td&gt;✅ default compiler&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;โบนัส&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Alias Paths กับ SWC&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SWC รองรับ alias paths ผ่านการตั้งค่าใน tsconfig.json หรือ jsconfig.json เช่น&lt;/li&gt;
&lt;li&gt;SWC จะอ่าน config นี้และทำงานร่วมกับ bundler (เช่น Next.js, Vite) เพื่อ resolve alias ได้&lt;/li&gt;
&lt;li&gt;แต่ SWC เองไม่มีระบบ plugin สำหรับ alias แบบ Babel (เช่น babel-plugin-module-resolver) ซึ่งอาจทำให้บางเคสละเอียดไม่ได้เหมือน Babel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SWC รองรับ alias paths แบบพื้นฐานผ่าน tsconfig.json ได้&lt;br&gt;
แต่ถ้า alias ซับซ้อนหรืออยากตั้งแบบละเอียด อาจต้องใช้ Babel plugin&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "compilerOptions": {
    /* alias path */
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@components/*": ["src/components/*"],
      "@utils/*": ["src/utils/*"]
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;i18n กับ SWC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;การทำ i18n โดยทั่วไปจะมี 2 แบบหลัก:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runtime i18n (เช่น react-intl, next-i18next) — SWC ไม่มีปัญหาเพราะเป็นโค้ด JavaScript ปกติ&lt;/li&gt;
&lt;li&gt;Compile-time i18n (เช่น babel-plugin-react-intl ที่ดึงข้อความแปลจาก source code แบบ static) — Babel Plugin นี้จะไม่ทำงานกับ SWC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;สรุป:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SWC ไม่รองรับ plugin สำหรับ compile-time extraction ของ i18n&lt;/li&gt;
&lt;li&gt;ถ้าต้องการทำ extraction อัตโนมัติ ต้องใช้ Babel หรือเครื่องมืออื่นร่วม&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;เรื่อง&lt;/th&gt;
&lt;th&gt;SWC&lt;/th&gt;
&lt;th&gt;Babel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alias Paths&lt;/td&gt;
&lt;td&gt;รองรับผ่าน tsconfig (พื้นฐาน)&lt;/td&gt;
&lt;td&gt;รองรับผ่าน plugin ละเอียดกว่า&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;i18n (runtime)&lt;/td&gt;
&lt;td&gt;รองรับ&lt;/td&gt;
&lt;td&gt;รองรับ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;i18n (compile-time extraction)&lt;/td&gt;
&lt;td&gt;ไม่รองรับ plugin&lt;/td&gt;
&lt;td&gt;รองรับ plugin&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>หยุด commit โค้ดพังๆ ด้วย Husky + Lint + Prettier แบบครบสูตร</title>
      <dc:creator>c_nooknook_daily_prompt</dc:creator>
      <pubDate>Wed, 18 Jun 2025 06:39:32 +0000</pubDate>
      <link>https://dev.to/nooknookwork/hyud-commit-okhdphang-dwy-husky-lint-prettier-aebbkhrbsuutr-oeo</link>
      <guid>https://dev.to/nooknookwork/hyud-commit-okhdphang-dwy-husky-lint-prettier-aebbkhrbsuutr-oeo</guid>
      <description>&lt;p&gt;&lt;strong&gt;"เคยไหม... commit โค้ดไปโดยลืมลบ console.log()&lt;br&gt;
หรือ push โค้ดที่ไม่ผ่าน lint ไปยัง production&lt;br&gt;
ถ้าเคย — คุณต้องรู้จัก Husky แล้วล่ะ!"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Husky เป็นเครื่องมือที่ช่วยให้เราใช้งาน Git Hooks ได้ง่ายขึ้น โดย Git Hooks คือสคริปต์ที่ Git เรียกใช้ในช่วงเวลาต่าง ๆ เช่น pre-commit, pre-push, commit-msg เพื่อให้เราสามารถตรวจสอบ หรือล็อกการกระทำบางอย่างไว้ก่อนจะเกิดขึ้น&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ติดตั้งผ่าน npm, yarn, หรือ pnpm ก็ได้ (ในที่นี้ใช้ pnpm เป็นตัวอย่าง)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm add -D husky
npx husky install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพิ่ม script prepare ใน package.json เพื่อให้ Husky พร้อมทำงานหลังติดตั้ง dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "scripts": {
    "prepare": "husky install"
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;จากนั้นรัน:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
pnpm run prepare

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;สร้าง pre-commit hook แบบง่าย ๆ&lt;/strong&gt;&lt;br&gt;
ตัวอย่าง: เช็ก lint ก่อน commit&lt;br&gt;
สร้างคำสั่ง lint ใน package.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{
  "scripts": {
    "lint": "eslint . --ext .ts,.tsx"
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สร้างไฟล์ pre-commit ด้วยคำสั่ง Husky:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npx husky add .husky/pre-commit "pnpm run lint"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตอนนี้ใน .husky/pre-commit จะมี:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

pnpm run lint

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ทุกครั้งที่คุณ git commit, Husky จะเช็ก lint ให้ก่อนอัตโนมัติ&lt;br&gt;
ถ้าโค้ดมี error หรือ warning ที่ตั้งไว้ strict — commit จะถูกบล็อก!&lt;/p&gt;

&lt;p&gt;เพิ่มความเทพด้วยหลายคำสั่ง&lt;br&gt;
เราสามารถเช็กหลายอย่างได้พร้อมกัน เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เช็ก lint&lt;/li&gt;
&lt;li&gt;Format ด้วย Prettier&lt;/li&gt;
&lt;li&gt;บล็อก console.log ด้วย ESLint rule
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx husky add .husky/pre-commit "pnpm run lint &amp;amp;&amp;amp; pnpm run format"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;ถ้ามีคำสั่งล้มเหลวเพียงคำสั่งเดียว — commit จะถูกยกเลิก&lt;/p&gt;

&lt;p&gt;ตัวอย่าง Prettier Format Script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{
  "scripts": {
    "format": "prettier --write ."
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพิ่มการบล็อก console.log() ด้วย ESLint&lt;br&gt;
ติดตั้ง plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
pnpm add -D eslint-plugin-no-console
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใน .eslintrc.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
module.exports = {
  plugins: ['no-console'],
  rules: {
    'no-console': ['error', { allow: ['warn', 'error'] }],
  },
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ทดสอบการทำงาน&lt;br&gt;
ลองเขียนโค้ดที่มี console.log() หรือผิด format&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ใช้ git add .&lt;/li&gt;
&lt;li&gt;ใช้ git commit -m "test commit"&lt;/li&gt;
&lt;li&gt;คุณจะเห็นว่า commit ถูกบล็อก พร้อมแสดง error ที่เกิดขึ้น&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;ตัวอย่างการใช้ commit-msg (เพิ่มเติม)&lt;/strong&gt;&lt;br&gt;
อยากให้ commit message เป็นแบบ conventional commits ใช่ไหม?&lt;/p&gt;

&lt;p&gt;ติดตั้ง commitlint&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm add -D @commitlint/{config-conventional,cli}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สร้าง commitlint.config.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
module.exports = {
  extends: ['@commitlint/config-conventional'],
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพิ่ม hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;สรุป&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;✅ สิ่งที่ได้จาก Husky&lt;/th&gt;
&lt;th&gt;🚫 สิ่งที่ป้องกัน&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;เพิ่มความมั่นใจให้ทีม&lt;/td&gt;
&lt;td&gt;commit โค้ดไม่ผ่าน lint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ลด bug จาก code style&lt;/td&gt;
&lt;td&gt;push โค้ดผิด format&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;รองรับ flow แบบทีมใหญ่&lt;/td&gt;
&lt;td&gt;commit message ไม่เป็นมาตรฐาน&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;"เขียนโค้ดให้ดีนั้นสำคัญ&lt;br&gt;
แต่ กันไม่ให้โค้ดพัง ตั้งแต่ก่อน commit — สำคัญยิ่งกว่า&lt;br&gt;
และ Husky ก็เป็นผู้ช่วยที่คุณจะหลงรักแน่นอน"&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
