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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- useContext สำหรับสถานะส่วนกลาง
- useReducer สำหรับสถานะที่ซับซ้อน
- useMemo และ useCallback เพื่อประสิทธิภาพ
- Custom Hooks: แยกตรรกะที่นำกลับมาใช้ซ้ำได้