0Pricing
Frontend Academy · บทเรียน

Custom Hooks: แยกตรรกะที่นำกลับมาใช้ซ้ำได้

ย้ายตรรกะที่มีสถานะไปไว้ในฟังก์ชัน custom use* เพื่อแชร์พฤติกรรมระหว่างคอมโพเนนต์โดยไม่ต้องทำโค้ดซ้ำหรือยกสถานะขึ้น

Custom Hooks: แยกตรรกะที่นำกลับมาใช้ซ้ำได้ เป็นบทเรียน Frontend Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Frontend Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Frontend Academy มีบทเรียนทั้งหมด 4 บทเรียน

ฮุกแบบกำหนดเองคืออะไร

ฮุกแบบกำหนดเองคือฟังก์ชัน JavaScript ที่ชื่อขึ้นต้นด้วย use และเรียกใช้ฮุกอื่นภายใน ฮุกแบบกำหนดเองช่วยแยกตรรกะที่มีสถานะออกมา เพื่อให้คอมโพเนนต์หลายตัวใช้ร่วมกันได้โดยไม่ต้องคัดลอกวาง

การแยกตรรกะไปไว้ในฮุกแบบกำหนดเอง

ระบุตรรกะที่ซ้ำกันในคอมโพเนนต์หลายตัว (การดึงข้อมูล + สถานะกำลังโหลด + ข้อผิดพลาด ขนาดหน้าต่าง พื้นที่จัดเก็บในเครื่อง) แล้ว ย้ายตรรกะนั้นไปไว้ในฮุกแบบกำหนดเอง

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handler = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handler);
    return () => window.removeEventListener('resize', handler);
  }, []);

  return width;
}

// Usage:
const width = useWindowWidth();
const isMobile = width < 768;

useFetch — ฮุกสำหรับดึงข้อมูล

ฮุกสำหรับดึงข้อมูลที่นำกลับมาใช้ใหม่ได้ ซึ่งคอมโพเนนต์ใด ๆ สามารถใช้โหลดข้อมูลจาก URL ได้

function useFetch<T>(url: string) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const controller = new AbortController();
    async function load() {
      try {
        const res = await fetch(url, { signal: controller.signal });
        if (!res.ok) throw new Error(`${res.status}`);
        setData(await res.json());
      } catch (err) {
        if ((err as DOMException).name !== 'AbortError')
          setError((err as Error).message);
      } finally { setLoading(false); }
    }
    load();
    return () => controller.abort();
  }, [url]);

  return { data, loading, error };
}

ฮุก useLocalStorage

ฮุกแบบกำหนดเองที่ซิงค์ค่าไปยัง localStorage และรักษาความสอดคล้องระหว่างแท็บต่าง ๆ ผ่านเหตุการณ์ storage

function useLocalStorage<T>(key: string, initialValue: T) {
  const [value, setValue] = useState<T>(() => {
    const stored = localStorage.getItem(key);
    return stored ? JSON.parse(stored) : initialValue;
  });

  const set = useCallback((newValue: T) => {
    setValue(newValue);
    localStorage.setItem(key, JSON.stringify(newValue));
  }, [key]);

  return [value, set] as const;
}

ฮุกแบบกำหนดเองใช้ตรรกะร่วมกัน ไม่ใช่สถานะร่วมกัน

คอมโพเนนต์แต่ละตัวที่เรียกใช้ฮุกแบบกำหนดเองจะมีสถานะอิสระของตัวเอง ฮุกไม่ใช่ซิงเกิลตัน แต่เป็นการเรียกฟังก์ชันที่สร้างอินสแตนซ์สถานะแยกกัน

หลักการตั้งชื่อ

ชื่อฮุกแบบกำหนดเองต้องขึ้นต้นด้วย use เรื่องนี้บังคับใช้โดยกฎตรวจสอบโค้ดของ ESLint สำหรับฮุกของ React ซึ่งรับรองว่าฮุกถูกเรียกที่ระดับบนสุดและตามลำดับที่ถูกต้อง

การส่งคืนหลายค่า

โดยทั่วไปฮุกแบบกำหนดเองจะคืนค่าเป็นอ็อบเจ็กต์ (ค่าที่มีชื่อ) หรือทูเพิล (เช่น useState) ทูเพิลช่วยให้แยกโครงสร้างพร้อมตั้งชื่อเองได้ ส่วนอ็อบเจ็กต์ช่วยอธิบายตัวเองได้ชัดเจน

// Tuple (like useState):
const [value, setValue] = useLocalStorage('key', 0);

// Object (more descriptive):
const { data, loading, error, refetch } = useFetch('/api/users');

ฮุก useDebounce

หน่วงค่าด้วย Debounce โดยจะอัปเดตค่าเฉพาะหลังจากผู้ใช้หยุดพิมพ์ตามระยะเวลาที่กำหนด

function useDebounce<T>(value: T, delay: number): T {
  const [debounced, setDebounced] = useState(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebounced(value), delay);
    return () => clearTimeout(timer);
  }, [value, delay]);

  return debounced;
}

// Usage:
const debouncedSearch = useDebounce(searchTerm, 300);
useEffect(() => { search(debouncedSearch); }, [debouncedSearch]);

ฮุก useMediaQuery

ครอบ window.matchMedia ไว้ในฮุก เพื่ออ่านผลลัพธ์ของมีเดียคิวรี CSS แบบตอบสนองต่อการเปลี่ยนแปลง

function useMediaQuery(query: string): boolean {
  const [matches, setMatches] = useState(() => window.matchMedia(query).matches);

  useEffect(() => {
    const mq = window.matchMedia(query);
    const handler = (e: MediaQueryListEvent) => setMatches(e.matches);
    mq.addEventListener('change', handler);
    return () => mq.removeEventListener('change', handler);
  }, [query]);

  return matches;
}

การทดสอบฮุกแบบกำหนดเอง

ใช้ยูทิลิตี @testing-library/react ชื่อ renderHook() เพื่อทดสอบฮุกแบบกำหนดเองแยกอิสระ โดยไม่ต้องครอบฮุกไว้ในคอมโพเนนต์

import { renderHook, act } from '@testing-library/react';

test('useCounter increments', () => {
  const { result } = renderHook(() => useCounter(0));
  expect(result.current.count).toBe(0);
  act(() => result.current.increment());
  expect(result.current.count).toBe(1);
});

ไลบรารีฮุกที่เผยแพร่แล้ว

ไลบรารีฮุกจากชุมชนมีฮุกที่ผ่านการทดสอบแล้วหลายร้อยรายการ เช่น @uidotdev/usehooks, react-use และ usehooks-ts ก่อนเขียนฮุกแบบกำหนดเอง ควรตรวจสอบก่อนว่ามีเวอร์ชันที่ผ่านการทดสอบมาเป็นอย่างดีอยู่แล้วหรือไม่

ตรวจสอบความเข้าใจ

สถานะภายในฮุกแบบกำหนดเองจะเป็นอย่างไรเมื่อคอมโพเนนต์สองตัวที่แตกต่างกันเรียกใช้ฮุกนั้น

ทบทวน: ฮุกแบบกำหนดเอง

ฮุกแบบกำหนดเองช่วยแยกตรรกะที่มีสถานะออกมาเพื่อใช้ซ้ำ ตั้งชื่อโดยใช้คำนำหน้า use คอมโพเนนต์แต่ละตัวที่เรียกใช้ฮุกจะมีสถานะอิสระของตัวเอง คืนค่าเป็นอ็อบเจ็กต์หรือทูเพิล รูปแบบที่ใช้บ่อย ได้แก่ useFetch, useLocalStorage, useDebounce และ useMediaQuery ทดสอบด้วย renderHook() ตรวจสอบไลบรารีจากชุมชนก่อนเขียนทุกอย่างขึ้นมาใหม่

คำถามที่พบบ่อย

บทเรียน “Custom Hooks: แยกตรรกะที่นำกลับมาใช้ซ้ำได้” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “Custom Hooks: แยกตรรกะที่นำกลับมาใช้ซ้ำได้” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Frontend Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Frontend Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “Custom Hooks: แยกตรรกะที่นำกลับมาใช้ซ้ำได้”

ย้ายตรรกะที่มีสถานะไปไว้ในฟังก์ชัน custom use* เพื่อแชร์พฤติกรรมระหว่างคอมโพเนนต์โดยไม่ต้องทำโค้ดซ้ำหรือยกสถานะขึ้น คุณปฏิบัติ Frontend Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Frontend Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Frontend Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “Custom Hooks: แยกตรรกะที่นำกลับมาใช้ซ้ำได้” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Frontend Academy นี้ได้ไหม

ได้ บทเรียน Frontend Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. useContext สำหรับสถานะส่วนกลาง
  2. useReducer สำหรับสถานะที่ซับซ้อน
  3. useMemo และ useCallback เพื่อประสิทธิภาพ
  4. Custom Hooks: แยกตรรกะที่นำกลับมาใช้ซ้ำได้
← กลับไปที่ Frontend Academy