Gensics

Back to Home

Custom Hooks ใน React: สร้างและใช้งาน

React Developer17 ธันวาคม 2567Advanced React
ReactCustom HooksReusabilityState Management

Custom Hooks เป็นวิธีการแยก logic ที่ใช้ stateful logic ออกมาให้ใช้ซ้ำได้ในหลาย components

สร้าง Custom Hook แรก

import { useState, useEffect } from 'react'; // Custom Hook สำหรับจัดการ localStorage function useLocalStorage(key, initialValue) { const [storedValue, setStoredValue] = useState(() => { try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { console.error('Error reading localStorage:', error); return initialValue; } }); const setValue = (value) => { try { setStoredValue(value); window.localStorage.setItem(key, JSON.stringify(value)); } catch (error) { console.error('Error setting localStorage:', error); } }; return [storedValue, setValue]; } // การใช้งาน function UserPreferences() { const [theme, setTheme] = useLocalStorage('theme', 'light'); const [language, setLanguage] = useLocalStorage('language', 'th'); return ( <div> <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}> Current theme: {theme} </button> <button onClick={() => setLanguage(language === 'th' ? 'en' : 'th')}> Current language: {language} </button> </div> ); }

Custom Hook สำหรับ API Calls

import { useState, useEffect } from 'react'; function useFetch(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { try { setLoading(true); setError(null); const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); setData(result); } catch (err) { setError(err.message); } finally { setLoading(false); } }; if (url) { fetchData(); } }, [url]); return { data, loading, error }; } // การใช้งาน function UserProfile({ userId }) { const { data: user, loading, error } = useFetch(`/api/users/${userId}`); if (loading) return <div>Loading...</div>; if (error) return <div>Error: {error}</div>; if (!user) return <div>No user found</div>; return ( <div> <h1>{user.name}</h1> <p>{user.email}</p> </div> ); }

Custom Hook สำหรับ Form Management

import { useState } from 'react'; function useForm(initialValues, validationRules = {}) { const [values, setValues] = useState(initialValues); const [errors, setErrors] = useState({}); const [touched, setTouched] = useState({}); const handleChange = (name, value) => { setValues(prev => ({ ...prev, [name]: value })); // Validate field if it has been touched if (touched[name] && validationRules[name]) { const error = validationRules[name](value); setErrors(prev => ({ ...prev, [name]: error })); } }; const handleBlur = (name) => { setTouched(prev => ({ ...prev, [name]: true })); // Validate on blur if (validationRules[name]) { const error = validationRules[name](values[name]); setErrors(prev => ({ ...prev, [name]: error })); } }; const validate = () => { const newErrors = {}; Object.keys(validationRules).forEach(name => { const error = validationRules[name](values[name]); if (error) newErrors[name] = error; }); setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const reset = () => { setValues(initialValues); setErrors({}); setTouched({}); }; return { values, errors, touched, handleChange, handleBlur, validate, reset }; } // การใช้งาน function ContactForm() { const { values, errors, handleChange, handleBlur, validate, reset } = useForm( { name: '', email: '', message: '' }, { name: (value) => !value ? 'Name is required' : '', email: (value) => { if (!value) return 'Email is required'; if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) { return 'Invalid email format'; } return ''; }, message: (value) => !value ? 'Message is required' : '' } ); const handleSubmit = (e) => { e.preventDefault(); if (validate()) { console.log('Form submitted:', values); reset(); } }; return ( <form onSubmit={handleSubmit}> <div> <input type="text" placeholder="Name" value={values.name} onChange={(e) => handleChange('name', e.target.value)} onBlur={() => handleBlur('name')} /> {errors.name && <span className="error">{errors.name}</span>} </div> <div> <input type="email" placeholder="Email" value={values.email} onChange={(e) => handleChange('email', e.target.value)} onBlur={() => handleBlur('email')} /> {errors.email && <span className="error">{errors.email}</span>} </div> <div> <textarea placeholder="Message" value={values.message} onChange={(e) => handleChange('message', e.target.value)} onBlur={() => handleBlur('message')} /> {errors.message && <span className="error">{errors.message}</span>} </div> <button type="submit">Submit</button> </form> ); }

Best Practices สำหรับ Custom Hooks

  1. ตั้งชื่อขึ้นต้นด้วย "use" - เป็น convention ของ React
  2. แยก logic ที่ซับซ้อนออกมา - ทำให้ component สะอาดขึ้น
  3. ทำให้ reusable - สามารถใช้ในหลาย components
  4. จัดการ cleanup อย่างถูกต้อง - ใช้ useEffect กับ cleanup function
  5. เขียน tests - Custom hooks ควรมี unit tests

สรุป

Custom Hooks เป็นเครื่องมือที่ทรงพลังสำหรับการแชร์ logic ระหว่าง components ช่วยให้โค้ดสะอาด อ่านง่าย และใช้ซ้ำได้