فارسی

بیاموزید چگونه از هوک‌های سفارشی ری‌اکت برای استخراج و استفاده مجدد منطق کامپوننت بهره ببرید و قابلیت نگهداری، تست‌پذیری و معماری کلی برنامه را بهبود بخشید.

هوک‌های سفارشی ری‌اکت: استخراج منطق کامپوننت برای استفاده مجدد

هوک‌های ری‌اکت روش نوشتن کامپوننت‌های ری‌اکت را متحول کرده‌اند و راهی زیباتر و کارآمدتر برای مدیریت وضعیت و اثرات جانبی ارائه می‌دهند. در میان هوک‌های مختلف موجود، هوک‌های سفارشی به عنوان ابزاری قدرتمند برای استخراج و استفاده مجدد منطق کامپوننت برجسته می‌شوند. این مقاله راهنمایی جامع برای درک و پیاده‌سازی هوک‌های سفارشی ری‌اکت ارائه می‌دهد و شما را قادر می‌سازد برنامه‌هایی با قابلیت نگهداری، تست‌پذیری و مقیاس‌پذیری بیشتر بسازید.

هوک‌های سفارشی ری‌اکت چیستند؟

در اصل، یک هوک سفارشی یک تابع جاوااسکریپت است که نام آن با "use" شروع می‌شود و می‌تواند هوک‌های دیگر را فراخوانی کند. این به شما امکان می‌دهد منطق کامپوننت را در توابع قابل استفاده مجدد استخراج کنید، در نتیجه تکرار کد را از بین می‌برد و ساختار کامپوننت تمیزتری را ترویج می‌دهد. برخلاف کامپوننت‌های معمولی ری‌اکت، هوک‌های سفارشی هیچ رابط کاربری را رندر نمی‌کنند؛ آن‌ها صرفاً منطق را کپسوله می‌کنند.

به آن‌ها به عنوان توابع قابل استفاده مجدد فکر کنید که می‌توانند به ویژگی‌های وضعیت و چرخه حیات ری‌اکت دسترسی داشته باشند. آن‌ها راهی فوق‌العاده برای اشتراک‌گذاری منطق حالت‌دار بین کامپوننت‌های مختلف بدون توسل به کامپوننت‌های سطح بالاتر (higher-order components) یا propهای رندر (render props) هستند که اغلب می‌توانند منجر به کدی شوند که خواندن و نگهداری آن دشوار است.

چرا از هوک‌های سفارشی استفاده کنیم؟

مزایای استفاده از هوک‌های سفارشی متعدد است:

ایجاد اولین هوک سفارشی

بیایید ایجاد و استفاده از یک هوک سفارشی را با یک مثال عملی نشان دهیم: دریافت داده از یک API.

مثال: useFetch - یک هوک دریافت داده

تصور کنید که اغلب نیاز به دریافت داده از APIهای مختلف در برنامه ری‌اکت خود دارید. به جای تکرار منطق دریافت در هر کامپوننت، می‌توانید یک هوک useFetch ایجاد کنید.


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 abortController = new AbortController();
    const signal = abortController.signal;

    const fetchData = async () => {
      setLoading(true);
      try {
        const response = await fetch(url, { signal: signal });
        if (!response.ok) {
          throw new Error(`HTTP error! Status: ${response.status}`);
        }
        const json = await response.json();
        setData(json);
        setError(null); // پاک کردن هرگونه خطای قبلی
      } catch (error) {
        if (error.name === 'AbortError') {
          console.log('Fetch aborted');
        } else {
          setError(error);
        }
        setData(null); // پاک کردن هرگونه داده قبلی
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    return () => {
      abortController.abort(); // تابع پاکسازی برای لغو دریافت در هنگام جداسازی یا تغییر URL
    };
  }, [url]); // اجرای مجدد اثر زمانی که URL تغییر می‌کند

  return { data, loading, error };
}

export default useFetch;

توضیح:

استفاده از هوک useFetch در یک کامپوننت

حالا بیایید ببینیم چگونه می‌توان از این هوک سفارشی در یک کامپوننت ری‌اکت استفاده کرد:


import React from 'react';
import useFetch from './useFetch';

function UserList() {
  const { data: users, loading, error } = useFetch('https://jsonplaceholder.typicode.com/users');

  if (loading) return <p>در حال بارگذاری کاربران...</p>;
  if (error) return <p>خطا: {error.message}</p>;
  if (!users) return <p>کاربری یافت نشد.</p>;

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name} ({user.email})</li>
      ))}
    </ul>
  );
}

export default UserList;

توضیح:

الگوهای پیشرفته هوک سفارشی

فراتر از دریافت داده‌های ساده، هوک‌های سفارشی می‌توانند برای کپسوله کردن منطق پیچیده‌تر استفاده شوند. در اینجا چند الگوی پیشرفته آورده شده است:

۱. مدیریت وضعیت با useReducer

برای سناریوهای پیچیده‌تر مدیریت وضعیت، می‌توانید هوک‌های سفارشی را با useReducer ترکیب کنید. این به شما امکان می‌دهد تا انتقال‌های وضعیت را به شیوه‌ای قابل پیش‌بینی‌تر و سازمان‌یافته‌تر مدیریت کنید.


import { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function useCounter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const increment = () => dispatch({ type: 'increment' });
  const decrement = () => dispatch({ type: 'decrement' });

  return { count: state.count, increment, decrement };
}

export default useCounter;

استفاده:


import React from 'react';
import useCounter from './useCounter';

function Counter() {
  const { count, increment, decrement } = useCounter();

  return (
    <div>
      <p>تعداد: {count}</p>
      <button onClick={increment}>افزایش</button>
      <button onClick={decrement}>کاهش</button>
    </div>
  );
}

export default Counter;

۲. ادغام Context با useContext

هوک‌های سفارشی همچنین می‌توانند برای ساده‌سازی دسترسی به Context ری‌اکت استفاده شوند. به جای استفاده مستقیم از useContext در کامپوننت‌های خود، می‌توانید یک هوک سفارشی ایجاد کنید که منطق دسترسی به Context را کپسوله کند.


import { useContext } from 'react';
import { ThemeContext } from './ThemeContext'; // فرض می‌شود ThemeContext دارید

function useTheme() {
  return useContext(ThemeContext);
}

export default useTheme;

استفاده:


import React from 'react';
import useTheme from './useTheme';

function MyComponent() {
  const { theme, toggleTheme } = useTheme();

  return (
    <div style={{ backgroundColor: theme.background, color: theme.color }}>
      <p>این کامپوننت من است.</p>
      <button onClick={toggleTheme}>تغییر تم</button>
    </div>
  );
}

export default MyComponent;

۳. Debouncing و Throttling

Debouncing و Throttling تکنیک‌هایی هستند که برای کنترل نرخ اجرای یک تابع استفاده می‌شوند. هوک‌های سفارشی می‌توانند برای کپسوله کردن این منطق استفاده شوند و اعمال این تکنیک‌ها را بر روی پردازشگرهای رویداد آسان کنند.


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

function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(handler);
    };
  }, [value, delay]);

  return debouncedValue;
}

export default useDebounce;

استفاده:


import React, { useState } from 'react';
import useDebounce from './useDebounce';

function SearchInput() {
  const [searchValue, setSearchValue] = useState('');
  const debouncedSearchValue = useDebounce(searchValue, 500); // Debounce برای ۵۰۰ میلی‌ثانیه

  useEffect(() => {
    // انجام جستجو با debouncedSearchValue
    console.log('در حال جستجو برای:', debouncedSearchValue);
    // console.log را با منطق جستجوی واقعی خود جایگزین کنید
  }, [debouncedSearchValue]);

  const handleChange = (event) => {
    setSearchValue(event.target.value);
  };

  return (
    <input
      type="text"
      value={searchValue}
      onChange={handleChange}
      placeholder="جستجو..."
    />
  );
}

export default SearchInput;

بهترین شیوه‌ها برای نوشتن هوک‌های سفارشی

برای اطمینان از اینکه هوک‌های سفارشی شما مؤثر و قابل نگهداری هستند، این بهترین شیوه‌ها را دنبال کنید:

ملاحظات جهانی

هنگام توسعه برنامه‌ها برای مخاطبان جهانی، موارد زیر را در نظر داشته باشید:

مثال: قالب‌بندی تاریخ بین‌المللی با یک هوک سفارشی


import { useState, useEffect } from 'react';
import { DateTimeFormat } from 'intl';

function useFormattedDate(date, locale) {
  const [formattedDate, setFormattedDate] = useState('');

  useEffect(() => {
    try {
      const formatter = new DateTimeFormat(locale, {
        year: 'numeric',
        month: 'long',
        day: 'numeric',
      });
      setFormattedDate(formatter.format(date));
    } catch (error) {
      console.error('خطا در قالب‌بندی تاریخ:', error);
      setFormattedDate('تاریخ نامعتبر');
    }
  }, [date, locale]);

  return formattedDate;
}

export default useFormattedDate;

استفاده:


import React from 'react';
import useFormattedDate from './useFormattedDate';

function MyComponent() {
  const today = new Date();
  const enDate = useFormattedDate(today, 'en-US');
  const frDate = useFormattedDate(today, 'fr-FR');
  const deDate = useFormattedDate(today, 'de-DE');

  return (
    <div>
      <p>تاریخ آمریکا: {enDate}</p>
      <p>تاریخ فرانسه: {frDate}</p>
      <p>تاریخ آلمان: {deDate}</p>
    </div>
  );
}

export default MyComponent;

نتیجه‌گیری

هوک‌های سفارشی ری‌اکت مکانیزم قدرتمندی برای استخراج و استفاده مجدد منطق کامپوننت هستند. با بهره‌گیری از هوک‌های سفارشی، می‌توانید کدی تمیزتر، قابل نگهداری‌تر و قابل تست‌تر بنویسید. با تسلط بیشتر بر ری‌اکت، تسلط بر هوک‌های سفارشی به طور قابل توجهی توانایی شما در ساخت برنامه‌های پیچیده و مقیاس‌پذیر را بهبود می‌بخشد. به یاد داشته باشید که بهترین شیوه‌ها را دنبال کنید و عوامل جهانی را هنگام توسعه هوک‌های سفارشی در نظر بگیرید تا اطمینان حاصل کنید که برای مخاطبان متنوع مؤثر و قابل دسترسی هستند. قدرت هوک‌های سفارشی را در آغوش بگیرید و مهارت‌های توسعه ری‌اکت خود را ارتقا دهید!