18: Fetch API & LocalStorage

เชื่อมต่อโลกกว้าง ดึงข้อมูลจริงจาก Server และเก็บความจำไว้ไม่ให้หายไปเมื่อปิดเว็บ

1. พนักงานรับส่งข้อมูล: Fetch API

fetch() คือคำสั่งในหน้าเว็บที่ใช้ ส่ง Request ไปขอข้อมูลจาก Server อื่น ๆ (API) กลับมาใช้งาน ซึ่งกระบวนการนี้ต้องใช้เวลาเดินทางผ่าน Network จึงต้องใช้ async / await เข้ามาช่วยเสมอ

ขั้นตอนการใช้ Fetch
  1. await fetch(url) : รอให้พนักงานเดินทางไปเอา "กล่องพัสดุ" กลับมาก่อน
  2. await response.json() : รอแกะกล่องพัสดุ แล้วแปลงข้อมูลข้างในให้อ่านออกเป็น Object (JSON)
JS
async function getPokemon() {
    try {
        // 1. ส่งพนักงานไปขอข้อมูล Pikachu (รอจนกว่าจะกลับมา)
        let response = await fetch("https://pokeapi.co/api/v2/pokemon/pikachu");
        
        // 2. แกะกล่องข้อมูล แปลงเป็น JS Object
        let data = await response.json(); 
        
        console.log("ชื่อ:", data.name);
        console.log("น้ำหนัก:", data.weight);
        console.log("รูปภาพ:", data.sprites.front_default);
        
    } catch (error) {
        console.error("ติดต่อ Server ไม่สำเร็จ:", error);
    }
}

2. กระเป๋าเก็บของของ Web Browser: LocalStorage

ปกติเวลาที่รีเฟรชหน้าเว็บ หรือปิดคอมพิวเตอร์ ข้อมูลในตัวแปร JavaScript จะหายวับไปหมด แต่ localStorage คือพื้นที่เก็บข้อมูลพิเศษใน Web Browser ที่ ปิดคอมคอมพิวเตอร์เปิดใหม่ ข้อมูลก็ยังคงอยู่

กฎเหล็กของ LocalStorage

เก็บได้เฉพาะ ข้อความ (String) เท่านั้น ถ้าจะเก็บ Array หรือ Object ต้องแปลงร่างมันก่อนด้วย JSON.stringify() และตอนดึงออกมาใช้ต้องแปลงกลับด้วย JSON.parse()

1. เก็บข้อมูล (Save)
JS
let myFav = { name: "Pikachu" };

// 1. แปลง Object เป็น String
let stringData = JSON.stringify(myFav);

// 2. เก็บลงกระเป๋า ตั้งชื่อว่า "fav_mon"
localStorage.setItem("fav_mon", stringData);
2. ดึงข้อมูล (Load)
JS
// 1. หยิบของตามชื่อป้าย
let data = localStorage.getItem("fav_mon");

if (data !== null) {
    // 2. แปลงกลับเป็น Object
    let myFav = JSON.parse(data); 
    console.log(myFav.name);
}
3. ลบข้อมูล (Delete)
JS
// ท่าที่ 1: เลือกลบแค่บางรายการ
localStorage.removeItem("fav_mon");

// ท่าที่ 2: ล้างบาง! ลบทุกอย่างของเว็บนี้
// (ใช้ด้วยความระมัดระวัง)
localStorage.clear();
LocalStorage vs Cookie

ทั้งคู่ใช้เก็บข้อมูลใน Browser เหมือนกัน แต่เกิดมาเพื่อหน้าที่ต่างกัน:

  • 🎒 LocalStorage คือ "กระเป๋าส่วนตัว": จุของได้เยอะ เก็บไว้ดูคนเดียว ฝั่ง Server จะไม่รู้ว่าในกระเป๋ามีอะไรบ้าง (จนกว่าจะเขียนโค้ดหยิบส่งไปให้)
  • 🏷️ Cookie คือ "ป้ายห้อยคอ": เขียนได้นิดเดียว แต่ทุกครั้งที่โหลดเว็บหรือดึง API ตัว Web Browser จะ "แนบป้ายนี้ส่งไปให้ Server อ่านอัตโนมัติ" เสมอ
คุณสมบัติ 🎒 LocalStorage 🏷️ Cookie
ขนาดความจุ ใหญ่ (~5 - 10 MB) เล็กมาก (~4 KB)
การแนบไป Server ไม่ส่งไปอัตโนมัติ ข้อมูลอยู่แค่ในเครื่อง (โหลดเว็บไว ไม่เปลืองเน็ต) ส่งไปอัตโนมัติ ทุกครั้งที่โหลดหน้าเว็บ หรือดึงข้อมูล
วันหมดอายุ ไม่มี (อยู่จนกว่าจะเขียนโค้ดสั่งลบ หรือผู้ใช้กด Clear เอง) ตั้งเวลาได้ (ถ้าไม่ตั้ง ปิดเบราว์เซอร์ปุ๊บหายปั๊บ)
ความปลอดภัย โดนดึงผ่าน JS ได้ง่าย
ห้ามเก็บรหัสผ่านหรือข้อมูลลับเด็ดขาด
ปลอดภัยกว่า
ตั้ง HttpOnly ป้องกันไม่ให้ JS แอบอ่านได้
เหมาะสำหรับ ตั้งค่าเว็บ (Dark Mode), ตะกร้าสินค้าชั่วคราว, แคชข้อมูลลดการดึง API ระบบ Login (Session ID), เก็บประวัติติดตามพฤติกรรม (Tracking)
เก็บแยกกันตาม Domain (เว็บไซต์)

Browser จะสร้างห้องเก็บของแยกให้แต่ละเว็บไซต์อย่างเด็ดขาด ข้อมูลที่เก็บไว้ใน youtube.com จะไม่สามารถถูกแอบอ่านหรือลบโดย facebook.com ได้

การความยินยอม (Consent)

แม้ในแง่เทคนิค Browser จะไม่เด้งหน้าต่างมาขออนุญาตผู้ใช้ แต่ ในทางกฎหมาย (PDPA) ถือว่า LocalStorage เทียบเท่า Cookie
📌 ฟังก์ชันพื้นฐาน (เช่น Dark mode): เก็บได้เลย ไม่ต้องขอ
📌 ใช้ติดตามตัว (Tracking/User ID): ต้องทำแบนเนอร์ให้กดยอมรับก่อนรันโค้ด


Workshop: สภาพอากาศ Real-time

ทดลองดึงอุณหภูมิปัจจุบันของ กรุงเทพมหานคร จาก Public API (Open-Meteo)

Requirements:
  1. สร้างปุ่มสำหรับโหลดข้อมูลสภาพอากาศ เมื่อคลิกที่ปุ่ม ให้ดึงข้อมูลจาก API
  2. พิกัดของขอนแก่น คือ (Lat 16.4322, Lon 102.8236) ให้ใช้ URL https://api.open-meteo.com/v1/forecast?latitude=16.4322&longitude=102.8236&current_weather=true สำหรับดึงข้อมูลสภาพอากาศของขอนแก่น ()
  3. ข้อมูลเวลา สามารถใช้ new Date("2026-02-21T13:45" + "Z").toLocaleTimeString('th-TH') เพื่อแปลงเป็นเวลาไทย
  4. เมื่อได้ข้อมูลจาก API ให้แสดงผลใน div
JS
<div id="weatherResult">
	<h6 class="text-muted text-uppercase fw-bold mb-1">Khonkaen, Thailand</h6>
	<div class="display-3 fw-bold text-dark mb-0">
		<span id="tempValue">--</span><span class="fs-1 text-muted">°C</span>
	</div>
	<p class="small text-muted mt-2 mb-0">อัปเดตล่าสุด: <span id="timeValue">--</span></p>
</div>
กดปุ่มเพื่อดึงข้อมูล API..
Practice Mission: สมุดภาพโปเกมอนส่วนตัว
สถานการณ์:

คุณคือนักผจญภัยที่กำลังรวบรวมรายชื่อโปเกมอน ให้สร้างระบบที่พิมพ์ชื่อโปเกมอน (ภาษาอังกฤษ) เพื่อดึงข้อมูลมาแสดงผล และเมื่อกดปุ่ม "บันทึกลงกระเป๋า" ให้เก็บชื่อโปเกมอนนั้นลง localStorage เพื่อให้รีเฟรชหน้าเว็บแล้วรายชื่อที่เคยเก็บไว้ยังอยู่ครบ

Pokedex Search
ยังไม่ได้ค้นหา..

กระเป๋าเก็บโปเกมอน
Requirements:
  1. Fetch: เมื่อกดค้นหา ให้ใช้ URL https://pokeapi.co/api/v2/pokemon/{ชื่อที่พิมพ์}
  2. Render: ถ้าเจอ ให้แสดงภาพ data.sprites.front_default และสร้างปุ่ม "บันทึก"
  3. Render: ถ้าไม่เจอ ให้แสดงข้อความว่าไม่พบโปเกมอนที่ค้นหา
  4. Save: เมื่อกดบันทึก ให้อ่าน Array เก่าจาก localStorage (ถ้ามี) จับชื่อนี้ยัดใส่ (Push) แล้ว Save ทับลงไปใหม่ (อย่าลืม JSON.stringify)
  5. Load: สร้างฟังก์ชัน loadFavorites() ให้ทำงานทันทีที่เปิดเว็บ เพื่อดึงข้อมูลจาก LocalStorage มาแสดงเป็น <li> ทันที