قدرت منطق قابل استفاده مجدد را در برنامههای ریاکت خود با هوکهای سفارشی آزاد کنید. یاد بگیرید چگونه برای کدی تمیزتر و قابل نگهداریتر، هوکهای سفارشی بسازید و از آنها بهره ببرید.
هوکهای سفارشی: الگوهای منطق قابل استفاده مجدد در ریاکت
هوکهای ریاکت با معرفی قابلیتهای state و lifecycle به کامپوننتهای تابعی، انقلابی در نحوه نوشتن کامپوننتهای ریاکت ایجاد کردند. در میان مزایای فراوانی که ارائه میدهند، هوکهای سفارشی به عنوان یک مکانیزم قدرتمند برای استخراج و استفاده مجدد از منطق در چندین کامپوننت برجسته هستند. این پست وبلاگ به طور عمیق به دنیای هوکهای سفارشی میپردازد و مزایا، نحوه ایجاد و استفاده از آنها را با مثالهای عملی بررسی میکند.
هوکهای سفارشی چه هستند؟
در اصل، یک هوک سفارشی یک تابع جاوا اسکریپت است که با کلمه "use" شروع میشود و میتواند هوکهای دیگر را فراخوانی کند. آنها به شما این امکان را میدهند که منطق کامپوننت را در توابع قابل استفاده مجدد استخراج کنید. این یک راه قدرتمند برای به اشتراک گذاشتن منطق دارای state، اثرات جانبی، یا سایر رفتارهای پیچیده بین کامپوننتها بدون توسل به render props، کامپوننتهای مرتبه بالاتر، یا الگوهای پیچیده دیگر است.
ویژگیهای کلیدی هوکهای سفارشی:
- قاعده نامگذاری: هوکهای سفارشی باید با کلمه "use" شروع شوند. این به ریاکت نشان میدهد که تابع حاوی هوک است و باید از قوانین هوکها پیروی کند.
- قابلیت استفاده مجدد: هدف اصلی، کپسولهسازی منطق قابل استفاده مجدد است تا اشتراکگذاری عملکرد بین کامپوننتها آسان شود.
- منطق دارای State: هوکهای سفارشی میتوانند با استفاده از هوک
useState
، state خود را مدیریت کنند و این امکان را فراهم میآورند که رفتارهای پیچیده دارای state را کپسوله کنند. - اثرات جانبی: آنها همچنین میتوانند با استفاده از هوک
useEffect
اثرات جانبی ایجاد کنند که امکان یکپارچهسازی با APIهای خارجی، واکشی دادهها و موارد دیگر را فراهم میکند. - قابلیت ترکیبپذیری: هوکهای سفارشی میتوانند هوکهای دیگر را فراخوانی کنند، که به شما امکان میدهد با ترکیب هوکهای کوچکتر و متمرکزتر، منطقهای پیچیدهتری بسازید.
مزایای استفاده از هوکهای سفارشی
هوکهای سفارشی چندین مزیت قابل توجه در توسعه ریاکت ارائه میدهند:
- قابلیت استفاده مجدد کد: واضحترین مزیت، توانایی استفاده مجدد از منطق در چندین کامپوننت است. این کار تکرار کد را کاهش میدهد و به یک پایگاه کد DRY (خودت را تکرار نکن) کمک میکند.
- خوانایی بهبود یافته: با استخراج منطق پیچیده به هوکهای سفارشی مجزا، کامپوننتهای شما تمیزتر و قابل فهمتر میشوند. منطق اصلی کامپوننت بر روی رندر کردن UI متمرکز باقی میماند.
- قابلیت نگهداری بهبود یافته: وقتی منطق در هوکهای سفارشی کپسوله میشود، تغییرات و رفع اشکالات را میتوان در یک مکان واحد اعمال کرد، که خطر ایجاد خطا در چندین کامپوننت را کاهش میدهد.
- قابلیت تستپذیری: هوکهای سفارشی را میتوان به راحتی به صورت مجزا تست کرد و اطمینان حاصل کرد که منطق قابل استفاده مجدد به طور مستقل از کامپوننتهایی که از آن استفاده میکنند، به درستی کار میکند.
- کامپوننتهای سادهتر: هوکهای سفارشی به مرتبسازی کامپوننتها کمک میکنند و آنها را کمتر پرحرف و بیشتر متمرکز بر هدف اصلی خود میکنند.
ایجاد اولین هوک سفارشی شما
بیایید ایجاد یک هوک سفارشی را با یک مثال عملی نشان دهیم: یک هوک که اندازه پنجره را ردیابی میکند.
مثال: useWindowSize
این هوک عرض و ارتفاع فعلی پنجره مرورگر را برمیگرداند. همچنین این مقادیر را هنگام تغییر اندازه پنجره بهروزرسانی میکند.
import { useState, useEffect } from 'react';
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
window.addEventListener('resize', handleResize);
// حذف شنونده رویداد هنگام پاکسازی
return () => window.removeEventListener('resize', handleResize);
}, []); // آرایه خالی تضمین میکند که effect فقط هنگام mount شدن اجرا شود
return windowSize;
}
export default useWindowSize;
توضیح:
- وارد کردن هوکهای لازم: ما
useState
وuseEffect
را از ریاکت وارد میکنیم. - تعریف هوک: ما یک تابع به نام
useWindowSize
ایجاد میکنیم که از قاعده نامگذاری پیروی میکند. - مقداردهی اولیه State: ما از
useState
برای مقداردهی اولیه statewindowSize
با عرض و ارتفاع اولیه پنجره استفاده میکنیم. - راهاندازی شنونده رویداد: ما از
useEffect
برای افزودن یک شنونده رویداد resize به پنجره استفاده میکنیم. هنگامی که اندازه پنجره تغییر میکند، تابعhandleResize
statewindowSize
را بهروزرسانی میکند. - پاکسازی: ما یک تابع پاکسازی از
useEffect
برمیگردانیم تا شنونده رویداد را هنگام unmount شدن کامپوننت حذف کنیم. این کار از نشت حافظه جلوگیری میکند. - مقادیر بازگشتی: هوک، شیء
windowSize
را که حاوی عرض و ارتفاع فعلی پنجره است، برمیگرداند.
استفاده از هوک سفارشی در یک کامپوننت
اکنون که هوک سفارشی خود را ایجاد کردهایم، بیایید ببینیم چگونه از آن در یک کامپوننت ریاکت استفاده کنیم.
import React from 'react';
import useWindowSize from './useWindowSize';
function MyComponent() {
const { width, height } = useWindowSize();
return (
عرض پنجره: {width}px
ارتفاع پنجره: {height}px
);
}
export default MyComponent;
توضیح:
- وارد کردن هوک: ما هوک سفارشی
useWindowSize
را وارد میکنیم. - فراخوانی هوک: ما هوک
useWindowSize
را درون کامپوننت فراخوانی میکنیم. - دسترسی به مقادیر: ما شیء بازگشتی را destructure میکنیم تا مقادیر
width
وheight
را بدست آوریم. - رندر کردن مقادیر: ما مقادیر عرض و ارتفاع را در UI کامپوننت رندر میکنیم.
هر کامپوننتی که از useWindowSize
استفاده کند، با تغییر اندازه پنجره به طور خودکار بهروزرسانی میشود.
مثالهای پیچیدهتر
بیایید چند مورد استفاده پیشرفتهتر برای هوکهای سفارشی را بررسی کنیم.
مثال: useLocalStorage
این هوک به شما اجازه میدهد تا به راحتی دادهها را از حافظه محلی (local storage) ذخیره و بازیابی کنید.
import { useState, useEffect } from 'react';
function useLocalStorage(key, initialValue) {
// State برای ذخیره مقدار ما
// ارسال مقدار اولیه به useState تا منطق فقط یک بار اجرا شود
const [storedValue, setStoredValue] = useState(() => {
try {
// دریافت از حافظه محلی با کلید
const item = window.localStorage.getItem(key);
// تجزیه json ذخیره شده یا در صورت عدم وجود، بازگرداندن initialValue
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// در صورت خطا نیز initialValue را بازگردان
console.log(error);
return initialValue;
}
});
// بازگرداندن یک نسخه بستهبندی شده از تابع setter هوک useState که ...
// ... مقدار جدید را در localStorage پایدار میکند.
const setValue = (value) => {
try {
// اجازه میدهد مقدار یک تابع باشد تا API مشابهی با useState داشته باشیم
const valueToStore = value instanceof Function ? value(storedValue) : value;
// ذخیره در حافظه محلی
window.localStorage.setItem(key, JSON.stringify(valueToStore));
// ذخیره state
setStoredValue(valueToStore);
} catch (error) {
// یک پیادهسازی پیشرفتهتر، مورد خطا را مدیریت میکند
console.log(error);
}
};
useEffect(() => {
try {
const item = window.localStorage.getItem(key);
setStoredValue(item ? JSON.parse(item) : initialValue);
} catch (error) {
console.log(error);
}
}, [key, initialValue]);
return [storedValue, setValue];
}
export default useLocalStorage;
نحوه استفاده:
import React from 'react';
import useLocalStorage from './useLocalStorage';
function MyComponent() {
const [name, setName] = useLocalStorage('name', 'Guest');
return (
سلام، {name}!
setName(e.target.value)}
/>
);
}
export default MyComponent;
مثال: useFetch
این هوک منطق واکشی داده از یک API را کپسوله میکند.
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`خطای HTTP! وضعیت: ${response.status}`);
}
const json = await response.json();
setData(json);
setLoading(false);
} catch (error) {
setError(error);
setLoading(false);
}
}
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
نحوه استفاده:
import React from 'react';
import useFetch from './useFetch';
function MyComponent() {
const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');
if (loading) return در حال بارگذاری...
;
if (error) return خطا: {error.message}
;
return (
عنوان: {data.title}
تکمیل شده: {data.completed ? 'بله' : 'خیر'}
);
}
export default MyComponent;
بهترین شیوهها برای هوکهای سفارشی
برای اطمینان از اینکه هوکهای سفارشی شما مؤثر و قابل نگهداری هستند، این بهترین شیوهها را دنبال کنید:
- آنها را متمرکز نگه دارید: هر هوک سفارشی باید یک هدف واحد و به خوبی تعریف شده داشته باشد. از ایجاد هوکهای بیش از حد پیچیده که سعی در انجام کارهای زیادی دارند، خودداری کنید.
- هوکهای خود را مستند کنید: مستندات واضح و مختصر برای هر هوک سفارشی ارائه دهید و هدف، ورودیها و خروجیهای آن را توضیح دهید.
- هوکهای خود را تست کنید: برای اطمینان از عملکرد صحیح و قابل اعتماد هوکهای سفارشی خود، تستهای واحد بنویسید.
- از نامهای توصیفی استفاده کنید: نامهای توصیفی برای هوکهای سفارشی خود انتخاب کنید که به وضوح هدف آنها را نشان دهد.
- خطاها را به درستی مدیریت کنید: مدیریت خطا را در هوکهای سفارشی خود پیادهسازی کنید تا از رفتار غیرمنتظره جلوگیری کرده و پیامهای خطای آموزنده ارائه دهید.
- قابلیت استفاده مجدد را در نظر بگیرید: هوکهای سفارشی خود را با در نظر گرفتن قابلیت استفاده مجدد طراحی کنید. آنها را به اندازه کافی عمومی بسازید تا در چندین کامپوننت قابل استفاده باشند.
- از انتزاع بیش از حد خودداری کنید: برای منطق سادهای که به راحتی در یک کامپوننت قابل مدیریت است، هوک سفارشی ایجاد نکنید. فقط منطقی را استخراج کنید که واقعاً قابل استفاده مجدد و پیچیده باشد.
اشتباهات رایج که باید از آنها اجتناب کرد
- شکستن قوانین هوکها: همیشه هوکها را در سطح بالای تابع هوک سفارشی خود فراخوانی کنید و فقط آنها را از کامپوننتهای تابعی ریاکت یا سایر هوکهای سفارشی فراخوانی کنید.
- نادیده گرفتن وابستگیها در useEffect: اطمینان حاصل کنید که تمام وابستگیهای لازم را در آرایه وابستگی هوک
useEffect
قرار دهید تا از closures کهنه و رفتار غیرمنتظره جلوگیری کنید. - ایجاد حلقههای بینهایت: هنگام بهروزرسانی state در یک هوک
useEffect
مراقب باشید، زیرا این کار به راحتی میتواند منجر به حلقههای بینهایت شود. اطمینان حاصل کنید که بهروزرسانی شرطی و بر اساس تغییرات در وابستگیها است. - فراموش کردن پاکسازی: همیشه یک تابع پاکسازی در
useEffect
قرار دهید تا شنوندگان رویداد را حذف کنید، اشتراکها را لغو کنید و سایر کارهای پاکسازی را برای جلوگیری از نشت حافظه انجام دهید.
الگوهای پیشرفته
ترکیب هوکهای سفارشی
هوکهای سفارشی را میتوان با هم ترکیب کرد تا منطق پیچیدهتری ایجاد شود. به عنوان مثال، میتوانید یک هوک useLocalStorage
را با یک هوک useFetch
ترکیب کنید تا دادههای واکشی شده را به طور خودکار در حافظه محلی ذخیره کنید.
اشتراکگذاری منطق بین هوکها
اگر چندین هوک سفارشی منطق مشترکی دارند، میتوانید آن منطق را در یک تابع ابزار جداگانه استخراج کرده و در هر دو هوک از آن استفاده مجدد کنید.
استفاده از Context با هوکهای سفارشی
هوکهای سفارشی را میتوان در ترکیب با React Context برای دسترسی و بهروزرسانی state سراسری استفاده کرد. این به شما امکان میدهد کامپوننتهای قابل استفاده مجددی ایجاد کنید که از state سراسری برنامه آگاه هستند و میتوانند با آن تعامل داشته باشند.
مثالهای دنیای واقعی
در اینجا چند نمونه از نحوه استفاده از هوکهای سفارشی در برنامههای دنیای واقعی آورده شده است:
- اعتبارسنجی فرم: یک هوک
useForm
برای مدیریت state فرم، اعتبارسنجی و ارسال ایجاد کنید. - احراز هویت: یک هوک
useAuth
برای مدیریت احراز هویت و مجوزهای کاربر پیادهسازی کنید. - مدیریت تم: یک هوک
useTheme
برای جابجایی بین تمهای مختلف (روشن، تیره و غیره) توسعه دهید. - موقعیتیابی جغرافیایی: یک هوک
useGeolocation
برای ردیابی موقعیت مکانی فعلی کاربر بسازید. - تشخیص اسکرول: یک هوک
useScroll
برای تشخیص زمانی که کاربر به نقطه خاصی از صفحه اسکرول کرده است، ایجاد کنید.
مثال: هوک useGeolocation برای برنامههای چندفرهنگی مانند نقشهبرداری یا خدمات تحویل
import { useState, useEffect } from 'react';
function useGeolocation() {
const [location, setLocation] = useState({
latitude: null,
longitude: null,
error: null,
});
useEffect(() => {
if (!navigator.geolocation) {
setLocation({
latitude: null,
longitude: null,
error: 'موقعیت یابی جغرافیایی توسط این مرورگر پشتیبانی نمیشود.',
});
return;
}
const watchId = navigator.geolocation.watchPosition(
(position) => {
setLocation({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
error: null,
});
},
(error) => {
setLocation({
latitude: null,
longitude: null,
error: error.message,
});
}
);
return () => navigator.geolocation.clearWatch(watchId);
}, []);
return location;
}
export default useGeolocation;
نتیجهگیری
هوکهای سفارشی ابزاری قدرتمند برای نوشتن کدهای ریاکت تمیزتر، قابل استفاده مجددتر و قابل نگهداریتر هستند. با کپسولهسازی منطق پیچیده در هوکهای سفارشی، میتوانید کامپوننتهای خود را ساده کنید، تکرار کد را کاهش دهید و ساختار کلی برنامههای خود را بهبود بخشید. هوکهای سفارشی را بپذیرید و پتانسیل آنها را برای ساخت برنامههای ریاکت قویتر و مقیاسپذیرتر آزاد کنید.
با شناسایی قسمتهایی در پایگاه کد فعلی خود شروع کنید که منطق در چندین کامپوننت تکرار میشود. سپس، آن منطق را به هوکهای سفارشی ریفکتور کنید. با گذشت زمان، شما کتابخانهای از هوکهای قابل استفاده مجدد خواهید ساخت که فرآیند توسعه شما را تسریع کرده و کیفیت کد شما را بهبود میبخشد.
به یاد داشته باشید که از بهترین شیوهها پیروی کنید، از اشتباهات رایج اجتناب کنید و الگوهای پیشرفته را برای بهرهبرداری حداکثری از هوکهای سفارشی کاوش کنید. با تمرین و تجربه، شما به یک استاد هوکهای سفارشی و یک توسعهدهنده ریاکت مؤثرتر تبدیل خواهید شد.