แสดงบทความที่มีป้ายกำกับ useState แสดงบทความทั้งหมด
แสดงบทความที่มีป้ายกำกับ useState แสดงบทความทั้งหมด

วันศุกร์ที่ 28 มีนาคม พ.ศ. 2568

🌙 การทำ Dark Mode ใน Next.js: ให้เว็บของคุณเท่ขึ้นแบบมืออาชีพ!

เบื่อไหม? กับเว็บที่สว่างจ้าจนตาล้า 😵‍💫 ถ้าคุณอยากให้ผู้ใช้เลือกได้ว่าอยากใช้ โหมดสว่าง (Light Mode) หรือ โหมดมืด (Dark Mode) ใน Next.js เรามีวิธีง่ายๆ ให้คุณลองทำ!

ในบทความนี้ เราจะมาเจาะลึก การทำ Dark Mode ใน Next.js แบบครบทุกวิธี ทั้งใช้ CSS Variables, useState, localStorage และไลบรารีเสริม เช่น Next Themes กับ Tailwind CSS พร้อมตัวอย่างโค้ดที่เอาไปใช้ได้เลย! 🚀


🔥 ทำไมต้องมี Dark Mode?

✅ ข้อดีของ Dark Mode

  • ช่วยลดอาการล้าสายตา 👀 (สำหรับคนที่ใช้เว็บตอนกลางคืน)
  • ประหยัดแบตเตอรี่ 🔋 (โดยเฉพาะจอ OLED)
  • ดูเท่! 😎 หลายเว็บใหญ่ๆ ก็ใช้ เช่น YouTube, Twitter


🛠 วิธีทำ Dark Mode ใน Next.js

🚀 1. ใช้ CSS Variables + useState

วิธีนี้เหมาะกับ:
✅ เว็บที่ไม่ซับซ้อนมาก
✅ ไม่ต้องใช้ไลบรารีเสริม


👨‍💻 ขั้นตอนการทำ

1️⃣ สร้าง globals.css และกำหนด Theme

แก้ไขไฟล์ styles/globals.css

:root {
  --bg-color: #ffffff;
  --text-color: #000000;
}

.dark-mode {
  --bg-color: #121212;
  --text-color: #ffffff;
}

body {
  background-color: var(--bg-color);
  color: var(--text-color);
  transition: background 0.3s, color 0.3s;
}

2️⃣ เพิ่มปุ่มสลับโหมดใน index.js

เปิดไฟล์ pages/index.js แล้วเพิ่มโค้ดนี้

import { useState } from "react";

export default function Home() {
  const [darkMode, setDarkMode] = useState(false);

  const toggleDarkMode = () => {
    setDarkMode(!darkMode);
    document.body.classList.toggle("dark-mode");
  };

  return (
    <div style={{ textAlign: "center", marginTop: "50px" }}>
      <h1>Dark Mode in Next.js 🌙</h1>
      <button
        onClick={toggleDarkMode}
        style={{
          padding: "10px 20px",
          fontSize: "18px",
          cursor: "pointer",
          background: darkMode ? "#fff" : "#333",
          color: darkMode ? "#000" : "#fff",
          border: "none",
          borderRadius: "5px",
        }}
      >
        {darkMode ? "Switch to Light Mode ☀️" : "Switch to Dark Mode 🌙"}
      </button>
    </div>
  );
}

🛠 2. ใช้ localStorage จำค่าโหมด

ปัญหา: ถ้ารีเฟรชหน้าเว็บ ค่าโหมดที่เลือกไว้จะหายไป
ทางแก้: ใช้ localStorage จำค่าการตั้งค่าของผู้ใช้

อัปเดตโค้ด index.js

import { useState, useEffect } from "react";

export default function Home() {
  const [darkMode, setDarkMode] = useState(false);

  useEffect(() => {
    const savedTheme = localStorage.getItem("theme");
    if (savedTheme === "dark") {
      setDarkMode(true);
      document.body.classList.add("dark-mode");
    }
  }, []);

  const toggleDarkMode = () => {
    setDarkMode(!darkMode);
    if (!darkMode) {
      document.body.classList.add("dark-mode");
      localStorage.setItem("theme", "dark");
    } else {
      document.body.classList.remove("dark-mode");
      localStorage.setItem("theme", "light");
    }
  };

  return (
    <div style={{ textAlign: "center", marginTop: "50px" }}>
      <h1>Dark Mode in Next.js 🌙</h1>
      <button
        onClick={toggleDarkMode}
        style={{
          padding: "10px 20px",
          fontSize: "18px",
          cursor: "pointer",
          background: darkMode ? "#fff" : "#333",
          color: darkMode ? "#000" : "#fff",
          border: "none",
          borderRadius: "5px",
        }}
      >
        {darkMode ? "Switch to Light Mode ☀️" : "Switch to Dark Mode 🌙"}
      </button>
    </div>
  );
}

✅ ข้อดี:

  • จำค่าธีมได้หลังจากรีเฟรช


🎨 3. ใช้ next-themes (แนะนำ!)

✅ ข้อดีของ next-themes

  • ใช้ง่ายมาก (ไม่ต้องเขียนโค้ดเยอะ)
  • รองรับ ระบบ Dark Mode อัตโนมัติจาก OS



🛠 ติดตั้ง next-themes

npm install next-themes


👨‍💻 ใช้งาน next-themes

1️⃣ แก้ไข _app.js

import { ThemeProvider } from "next-themes";

export default function MyApp({ Component, pageProps }) {
  return (
    <ThemeProvider attribute="class">
      <Component {...pageProps} />
    </ThemeProvider>
  );
}

2️⃣ แก้ไข index.js

import { useTheme } from "next-themes";
import { useEffect, useState } from "react";

export default function Home() {
  const { theme, setTheme } = useTheme();
  const [mounted, setMounted] = useState(false);

  useEffect(() => setMounted(true), []);

  if (!mounted) return null; // ป้องกัน Hydration Error

  return (
    <div className="p-5 text-center">
      <h1 className="text-2xl">Dark Mode with next-themes 🌙</h1>
      <button
        onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
        className="mt-3 px-4 py-2 text-white bg-black rounded"
      >
        {theme === "dark" ? "Switch to Light Mode ☀️" : "Switch to Dark Mode 🌙"}
      </button>
    </div>
  );
}

🔥 ง่ายสุดๆ แค่เรียก setTheme() แล้วปล่อยให้ next-themes จัดการให้!

🏁 สรุป

วิธี ข้อดี ข้อเสีย
CSS Variables + useState ง่าย, ไม่ต้องใช้ไลบรารี รีเฟรชแล้วค่าหาย
localStorage จำค่าธีมได้หลังรีเฟรช ต้องใช้ useEffect
next-themes (แนะนำ) รองรับ Dark Mode อัตโนมัติ ต้องติดตั้งไลบรารี

🎯 ถ้าคุณอยากทำ Dark Mode แบบง่ายสุด 👉 ใช้ next-themes
🎯 ถ้าอยากควบคุมเองทั้งหมด 👉 ใช้ CSS Variables + localStorage

🚀 ลองทำเลย แล้วเว็บของคุณจะดูโปรขึ้น 300%!! 😆

วันศุกร์ที่ 28 กุมภาพันธ์ พ.ศ. 2568

การใช้ useEffect และ useState สำหรับ Client-side Rendering (CSR)

ถ้าคุณเป็นสาย React น่าจะคุ้นเคยกับการใช้ useState และ useEffect กันอยู่แล้ว แต่เคยสงสัยไหมว่า เวลาเราทำ Client-side Rendering (CSR) ควรใช้สองตัวนี้ยังไงให้ถูกต้อง?

ในบทความนี้ เราจะมาดูวิธีใช้ useState และ useEffect ในการจัดการข้อมูลแบบ CSR (Client-side Rendering) พร้อมตัวอย่างโค้ดจริง และข้อควรระวังที่ต้องระวัง ถ้าพร้อมแล้ว ไปดูกันเลย! 🚀

🎯 Client-side Rendering (CSR) คืออะไร?

ก่อนจะไปดู useState และ useEffect มาทำความเข้าใจ CSR (Client-side Rendering) กันก่อน

📌 CSR คือการเรนเดอร์หน้าเว็บบนฝั่งไคลเอนต์ (Client-side) โดยใช้ JavaScript ซึ่งหมายความว่า ทุกอย่างถูกโหลดผ่านเบราว์เซอร์ แทนที่จะให้เซิร์ฟเวอร์ส่งหน้า HTML มาให้แบบสมบูรณ์

🔍 ลักษณะของ CSR:

  • เมื่อเข้าเว็บครั้งแรก เบราว์เซอร์จะโหลดไฟล์ HTML + JavaScript
  • JavaScript จะรันบนฝั่งไคลเอนต์ เพื่อสร้าง UI และดึงข้อมูลจาก API
  • เหมาะกับแอปที่ต้องการ อินเตอร์แอคทีฟสูง เช่น Dashboard หรือ Web App
  • แต่ SEO อาจไม่ดี เพราะหน้าเว็บไม่มีข้อมูล HTML ให้บอทอ่าน (ต้องใช้ Next.js + SSR/SSG แก้ปัญหา)


🛠 การใช้ useState และ useEffect สำหรับ CSR

📌 useState คืออะไร?

useState เป็น React Hook ที่ใช้จัดการ state (ข้อมูลที่เปลี่ยนแปลงได้) ในคอมโพเนนต์ ฟังก์ชันนี้ช่วยให้เราสร้างตัวแปร state และอัปเดตค่าได้ง่าย ๆ

📌 useEffect คืออะไร?

useEffect เป็น React Hook ที่ใช้จัดการ side effects เช่น

  • เรียก API
  • เปลี่ยนชื่อเอกสาร (document.title)
  • ตั้งค่า setTimeout หรือ setInterval


🏗 ตัวอย่างการใช้ useState และ useEffect ใน CSR

มาดูกันว่า เราสามารถใช้ useState และ useEffect ใน CSR ได้ยังไง โดยสมมติว่าเราต้องการ ดึงข้อมูลผู้ใช้จาก API และแสดงผลในเว็บ

1. โหลดข้อมูลจาก API ด้วย useEffect

import React, { useState, useEffect } from 'react';

const UsersList = () => {
  const [users, setUsers] = useState([]); // ใช้ useState เก็บข้อมูลผู้ใช้
  const [loading, setLoading] = useState(true); // ใช้ state เช็กว่ากำลังโหลดข้อมูลอยู่ไหม

  useEffect(() => {
    // ดึงข้อมูลจาก API เมื่อคอมโพเนนต์โหลดครั้งแรก
    fetch('https://jsonplaceholder.typicode.com/users')
      .then((response) => response.json())
      .then((data) => {
        setUsers(data); // อัปเดต state
        setLoading(false); // ปิดสถานะ loading
      });
  }, []); // ใส่ [] หมายความว่าจะรันแค่ครั้งเดียวตอนโหลดหน้า

  return (
    <div>
      <h1>รายชื่อผู้ใช้</h1>
      {loading ? <p>กำลังโหลดข้อมูล...</p> : null}
      <ul>
        {users.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default UsersList;

🔍 อธิบายโค้ด

  • ใช้ useState([]) เพื่อเก็บข้อมูลผู้ใช้
  • ใช้ useEffect เพื่อเรียก API ตอนคอมโพเนนต์โหลดครั้งแรก
  • ใช้ setUsers(data) เพื่ออัปเดตข้อมูล
  • ใช้ setLoading(false) เพื่อปิดสถานะโหลด


2. ใช้ useEffect จัดการ Event Listener

สมมติว่าเราต้องการให้หน้าเว็บ เช็กขนาดหน้าจอ (window size) และอัปเดตทุกครั้งที่เปลี่ยนขนาด

import React, { useState, useEffect } from 'react';

const WindowSize = () => {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);

    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize); // ลบ Event Listener ตอนคอมโพเนนต์ unmount
    };
  }, []);

  return (
    <div>
      <h1>ขนาดหน้าจอ: {width}px</h1>
    </div>
  );
};

export default WindowSize;

🔍 อธิบายโค้ด

  • ใช้ useState เพื่อเก็บค่าความกว้างของหน้าจอ
  • ใช้ useEffect เพิ่ม event listener resize ตอนโหลด
  • ใช้ return () => {} เพื่อลบ event listener ตอนคอมโพเนนต์ถูกถอดออก


🔥 ข้อควรระวังในการใช้ useEffect และ useState

⚠️ 1. อย่าดึง API ใน useEffect แบบไม่มี Dependency Array

ถ้าคุณลืมใส่ [] มันจะรันซ้ำ ทุกครั้งที่คอมโพเนนต์ re-render ทำให้ API ถูกเรียกหลายรอบเกินไป

❌ โค้ดผิด:

useEffect(() => {
  fetchData(); // จะเรียก API ทุกครั้งที่ state เปลี่ยน
});

✅ โค้ดที่ถูกต้อง:

useEffect(() => {
  fetchData(); // เรียก API แค่ครั้งเดียว
}, []);

⚠️ 2. อย่าอัปเดต state ใน useEffect โดยไม่มีเงื่อนไข

ถ้าเราอัปเดต state โดยไม่มีเงื่อนไข มันจะทำให้เกิด Infinite Loop ได้

❌ โค้ดผิด:

useEffect(() => {
  setCount(count + 1); // ทำให้เกิดลูป เพราะการอัปเดต state ทำให้ useEffect รันใหม่
}, [count]);

✅ โค้ดที่ถูกต้อง:

useEffect(() => {
  if (count < 10) setCount(count + 1);
}, [count]); // ตรวจสอบก่อนอัปเดต state


📌 สรุป

  • useState ใช้เก็บข้อมูลที่เปลี่ยนแปลงได้ในคอมโพเนนต์
  • useEffect ใช้ดึงข้อมูลจาก API, จัดการ Event Listener, และทำงานที่ต้องเกิดหลังจาก render
  • CSR เหมาะกับเว็บที่ต้องการโต้ตอบเยอะ แต่ไม่เหมาะกับ SEO
  • ควรระวังการใช้ useEffect ไม่ให้เกิด Infinite Loop หรือ API ถูกเรียกซ้ำ

ถ้าคุณเข้าใจการใช้ useState และ useEffect แล้ว คุณสามารถพัฒนาเว็บแบบ CSR ได้อย่างมีประสิทธิภาพ 🚀

การใช้ Image Optimization ใน Next.js: โหลดไว SEO ดี ประหยัดแบนด์วิธ!

เคยเจอปัญหาเว็บโหลดช้าเพราะรูปภาพขนาดใหญ่หรือเปล่า? 📷 ถ้าใช่ Next.js มีฟีเจอร์ Image Optimization ที่ช่วยให้รูปภาพโหลดเร็วขึ้น อัตโนมัติ ไม...