021-88881776

آموزش Hooks React

در آموزش React، یکی از ویژگی‌های کلیدی و پیشرفته که به توسعه‌دهندگان امکان مدیریت بهتر وضعیت و چرخه عمر اجزای توابعی را می‌دهد، Hooks React است. Hooks React بدون نیاز به کلاس‌ها، قابلیت‌های مهمی مانند مدیریت state و اثرها (effects) را به اجزای توابع اضافه می‌کند. این مقاله از سطح مبتدی تا پیشرفته تمامی جنبه‌های Hooks React را با توضیحات ساده و مثال‌های عملی پوشش می‌دهد تا به درک بهتر شما از این مفهوم کمک کند.

آشنایی با Hook‌ها

React Hooks در سال ۲۰۱۸ و در نسخه ۱۶.۸ React معرفی شدند و انقلابی در نحوه ساخت و مدیریت اجزای توابعی (Functional Components) به وجود آوردند. پیش از این، ویژگی‌های پیشرفته مانند مدیریت state و چرخه عمر (Lifecycle) تنها در اجزای کلاسی (Class Components) در دسترس بود. Hooks این امکانات را به توابع نیز اضافه کرد، به طوری که توسعه‌دهندگان بدون نیاز به کلاس‌ها می‌توانند از ویژگی‌های قدرتمند React بهره ببرند.

چه چیزی باعث محبوبیت Hook‌ها شد؟

React Hooks با تغییر شیوه توسعه اجزا در React، محبوبیت زیادی پیدا کرد. دلایل زیر به محبوبیت Hooks کمک کردند:

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

کاهش پیچیدگی اجزای کلاسی: کلاس‌ها معمولاً شامل منطق پیچیده‌ای هستند که باعث می‌شود کد سخت‌تر خوانده و نگهداری شود. Hooks امکان استفاده از state و سایر ویژگی‌ها را بدون نیاز به کلاس فراهم می‌کند و پیچیدگی‌های مربوط به توابع this و ساختارهای پیچیده کلاس‌ها را از بین می‌برد.

امکان استفاده مجدد از منطق: یکی از محدودیت‌های اجزای کلاسی این است که شما نمی‌توانید به سادگی منطق را بین اجزا به اشتراک بگذارید. با Hooks، می‌توانید Hook‌های سفارشی (Custom Hooks) ایجاد کنید و از آن‌ها در بخش‌های مختلف برنامه استفاده کنید. این به اشتراک‌گذاری منطق بین اجزا را به سادگی و کارآمدی امکان‌پذیر می‌کند.

استقلال بیشتر از ساختار کلاس‌ها: Hooks به توسعه‌دهندگان این امکان را می‌دهند که بدون وابستگی به ساختار کلاس، از ویژگی‌های React استفاده کنند. این موضوع باعث می‌شود که کد کمتر وابسته به مفاهیم کلاس‌ها و بیشتر به توابع مدرن نزدیک شود.

نحوه استفاده از Hook‌ها

React شامل Hook‌های مختلفی است که هر یک وظیفه خاصی را انجام می‌دهند. این Hooks را می‌توان به دو دسته اصلی تقسیم کرد:

Hook‌های اصلی (Primary Hooks): این دسته شامل Hooks پایه‌ای است که برای مدیریت وضعیت (state) و چرخه عمر (effect) استفاده می‌شوند. Hook‌های اصلی شامل useState، useEffect، useContext و useRef هستند.

Hook‌های پیشرفته یا کمکی (Additional Hooks): این Hooks امکانات بیشتری را برای توسعه‌دهندگان فراهم می‌کنند و شامل useReducer، useCallback، useMemo، useLayoutEffect و useDebugValue هستند. این Hooks برای بهینه‌سازی عملکرد، مدیریت state پیچیده، و اشکال‌زدایی استفاده می‌شوند.

چند قاعده مهم در استفاده از Hook‌ها

برای استفاده از Hooks، باید به دو قانون کلیدی پایبند باشید:

فقط در بالاترین سطح تابع از Hook‌ها استفاده کنید: یعنی نباید Hooks را درون حلقه‌ها، شرایط (if-else)، یا توابع تو در تویی قرار دهید. این موضوع به React کمک می‌کند تا Hook‌ها را به ترتیب مشابه در هر بار رندر به یاد بیاورد.

فقط در اجزای توابعی یا Hook‌های سفارشی از Hook‌ها استفاده کنید: Hooks فقط باید در داخل اجزای توابعی (Function Components) و Hook‌های سفارشی (Custom Hooks) استفاده شوند، نه در توابع معمولی یا اجزای کلاسی.

این قوانین تضمین می‌کنند که Hooks به درستی کار کنند و برنامه شما با رفتار غیرقابل پیش‌بینی مواجه نشود.

معرفی چند Hook مهم و کاربرد آن‌ها

React چندین Hook اصلی و پراستفاده را ارائه می‌دهد که هرکدام ویژگی خاصی را به اجزای توابعی اضافه می‌کنند:

useState: برای مدیریت وضعیت‌های ساده (مانند شمارنده‌ها، فرم‌ها و …) استفاده می‌شود.

useEffect: برای انجام عملیات‌های جانبی مانند فراخوانی API، تنظیم تایمرها یا مدیریت چرخه عمر اجزا استفاده می‌شود.

useContext: برای استفاده از context در اجزا بدون نیاز به استفاده از Context.Consumer، که دسترسی به context را ساده‌تر می‌کند.

useReducer: برای مدیریت وضعیت‌های پیچیده‌تر، به ویژه در مواقعی که منطق وضعیت چند مرحله‌ای و پیچیده است.

useMemo و useCallback: برای بهینه‌سازی عملکرد کاربرد دارند و با جلوگیری از محاسبات یا فراخوانی‌های غیرضروری، عملکرد برنامه را بهبود می‌بخشند.

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

استفاده از useState

useState یکی از اولین و پراستفاده‌ترین Hooks React است که برای مدیریت state در اجزای توابعی (Functional Components) به کار می‌رود. در گذشته، برای استفاده از state، نیاز به ایجاد اجزای کلاسی بود، اما useState این امکان را فراهم کرد که بدون استفاده از کلاس‌ها، state را مستقیماً در اجزای توابعی تعریف و مدیریت کنید. state در واقع یک نوع داده متغیر است که می‌تواند در طول زمان تغییر کند و React هنگام تغییر state، کامپوننت را مجدداً رندر می‌کند تا تغییرات را نشان دهد.

نحوه استفاده از useState

برای استفاده از useState، آن را از React وارد کرده و سپس با استفاده از سینتکس آرایه‌ای، یک متغیر state و تابع به‌روزرسانی آن را تعریف می‌کنید. useState یک مقدار اولیه می‌پذیرد و این مقدار اولیه به متغیر state اختصاص داده می‌شود.

سینتکس

const [state, setState] = useState(initialValue);

state: متغیری که مقدار کنونی state را در خود نگه می‌دارد.
setState: تابعی که برای به‌روزرسانی state استفاده می‌شود.
initialValue: مقدار اولیه‌ای که state در اولین بار با آن مقداردهی می‌شود.
مثال: ساخت یک شمارنده با استفاده از useState
در مثال زیر، useState برای ایجاد یک شمارنده استفاده شده است. مقدار اولیه state صفر است و دکمه‌ای قرار داده شده که با هر کلیک، مقدار شمارنده را یک واحد افزایش می‌دهد.

import React, { useState } from 'react';

function Counter() {
  // تعریف state با مقدار اولیه 0
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increase</button>
    </div>
  );
}

در این مثال:

متغیر count مقدار کنونی شمارنده را نگه می‌دارد.
تابع setCount برای به‌روزرسانی مقدار شمارنده استفاده می‌شود.
هر بار که روی دکمه “Increase” کلیک می‌شود، تابع setCount فراخوانی می‌شود و مقدار جدیدی به state اختصاص می‌دهد.

نحوه به‌روزرسانی state با استفاده از setState

تابع setState می‌تواند به دو روش مختلف برای به‌روزرسانی state استفاده شود:

انتقال مقدار جدید: می‌توانید مقدار جدید state را مستقیماً به setState بدهید.

setCount(count + 1);

استفاده از تابع به‌روزرسانی: اگر مقدار جدید state به مقدار قبلی وابسته باشد، می‌توانید یک تابع به setState ارسال کنید که از مقدار قبلی استفاده می‌کند. این روش مخصوصاً در مواقعی که به طور همزمان چندین بار setState فراخوانی می‌شود، مفید است.

setCount((prevCount) => prevCount + 1);

استفاده از تابع به‌روزرسانی به React کمک می‌کند تا تغییرات را به درستی مدیریت کند و از بروز مشکلات مربوط به همزمانی جلوگیری می‌کند.

نکات مهم در استفاده از useState

مقداردهی اولیه فقط در اولین رندر: مقدار اولیه که به useState می‌دهید، فقط در اولین رندر کامپوننت اعمال می‌شود. پس از آن، تغییرات فقط از طریق setState صورت می‌گیرد.

همزمانی و غیر همزمانی: setState به صورت غیر همزمان اجرا می‌شود و ممکن است فوراً بعد از فراخوانی اعمال نشود. به همین دلیل، استفاده از تابع به‌روزرسانی برای دسترسی به مقدار قبلی state توصیه می‌شود.

استفاده از چندین useState: در یک کامپوننت می‌توانید از چندین useState استفاده کنید. این کار به شما اجازه می‌دهد که stateهای مختلفی با کارکردهای مختلف داشته باشید.

مقادیر پیچیده: useState می‌تواند برای مقادیر پیچیده مانند اشیاء و آرایه‌ها نیز استفاده شود. در این موارد، معمولاً باید مقادیر قبلی را با استفاده از تابع به‌روزرسانی، حفظ کنید تا از تغییرات ناخواسته جلوگیری شود.

مثال پیشرفته: مدیریت چندین state با استفاده از useState
در مثال زیر، از useState برای مدیریت چندین state مانند name و age استفاده می‌شود.

import React, { useState } from 'react';

function UserInfo() {
  const [name, setName] = useState('');
  const [age, setAge] = useState(0);

  return (
    <div>
      <input 
        type="text" 
        placeholder="Name" 
        value={name} 
        onChange={(e) => setName(e.target.value)} 
      />
      <input 
        type="number" 
        placeholder="Age" 
        value={age} 
        onChange={(e) => setAge(Number(e.target.value))} 
      />
      <p>Name: {name}</p>
      <p>Age: {age}</p>
    </div>
  );
}

در این مثال:

stateهای name و age به ترتیب برای نگه‌داشتن نام و سن کاربر تعریف شده‌اند.
هر فیلد ورودی به تغییر state مربوط به خود واکنش نشان می‌دهد و مقدار state را با هر تغییر به‌روزرسانی می‌کند.
useState یکی از Hooks React بسیار ساده و مفید است که به توسعه‌دهندگان اجازه می‌دهد به راحتی state را در اجزای توابعی مدیریت کنند. از این Hook می‌توان برای مقادیر مختلف و مقاصد متنوع مانند کنترل فرم‌ها، شمارنده‌ها و غیره استفاده کرد. با درک کامل useState و نحوه به‌روزرسانی آن، می‌توانید مدیریت state را در پروژه‌های React خود به طور کارآمدی انجام دهید و تجربه کاربری بهتری را ارائه دهید.

استفاده از useEffect

useEffect یکی از Hooks React بسیار کاربردی و مهم است که برای انجام عملیات‌های جانبی (Side Effects) در اجزای توابعی به کار می‌رود. عملیات جانبی به آن دسته از کدهایی گفته می‌شود که خارج از فرآیند رندر عادی اجزا اجرا می‌شوند و شامل کارهایی مانند فراخوانی API، دستکاری مستقیم DOM، تنظیم تایمرها، و حتی پاک‌سازی (cleanup) منابعی مانند event listeners است. با استفاده از useEffect، شما می‌توانید به تغییرات state و props واکنش نشان دهید و منطق خاصی را در هنگام تغییر این مقادیر اجرا کنید.

نحوه استفاده از useEffect

useEffect به شما امکان می‌دهد که قطعه کدی را در هنگام رندر شدن اجزا، و همچنین زمانی که مقدار state یا props خاصی تغییر می‌کند، اجرا کنید. این Hook یک تابع را به عنوان آرگومان اول می‌پذیرد که این تابع شامل منطق عملیات جانبی شما است. useEffect همچنین یک آرایه وابستگی (Dependency Array) به عنوان آرگومان دوم می‌پذیرد که تعیین می‌کند این Hook در چه زمان‌هایی اجرا شود.

سینتکس کلی

useEffect(() => {
  // عملیات جانبی

  return () => {
    // عملیات پاک‌سازی (اختیاری)
  };
}, [dependencies]);

تابع اصلی: در بدنه این تابع، عملیات‌های جانبی مانند فراخوانی API یا دستکاری DOM را قرار می‌دهید.
تابع بازگشتی (پاک‌سازی): تابعی که به منظور پاک‌سازی منابع یا لغو عملیات‌های در حال اجرا تعریف می‌شود. این تابع در زمان حذف کامپوننت از DOM یا زمانی که وابستگی‌ها تغییر می‌کنند اجرا می‌شود.
آرایه وابستگی‌ها: این آرایه تعیین می‌کند که Hook چه زمانی اجرا شود. اگر این آرایه خالی باشد، useEffect تنها در زمان بارگذاری اولیه اجرا می‌شود. اگر وابستگی‌هایی داشته باشد، هر بار که این وابستگی‌ها تغییر کنند، Hook دوباره اجرا می‌شود.

انواع کاربردهای useEffect

useEffect به دلیل انعطاف‌پذیری بالا، در کاربردهای متنوعی استفاده می‌شود:

فراخوانی API: برای بارگذاری داده‌ها از یک API خارجی به طور همزمان با بارگذاری اولیه صفحه یا در هنگام تغییر props خاص استفاده می‌شود.

تنظیم تایمر و Interval: می‌توان با استفاده از setInterval و setTimeout تایمرها یا وظایف تکراری را تنظیم کرد. این کاربرد معمولاً به عملیات پاک‌سازی نیز نیاز دارد تا در زمان خروج از صفحه یا حذف کامپوننت، تایمرها لغو شوند.

واکنش به تغییرات state یا props: هر بار که state یا props مشخصی تغییر کند، می‌توانید با قرار دادن این متغیرها در آرایه وابستگی‌ها، منطق خاصی را اجرا کنید.

پاک‌سازی منابع و لغو عملیات‌ها: در کاربردهایی مانند تنظیم event listeners یا کار با WebSocket، نیاز است که هنگام حذف کامپوننت، این منابع پاک‌سازی شوند تا از مشکلاتی مانند memory leak جلوگیری شود.

مثال: فراخوانی API با استفاده از useEffect
در مثال زیر، useEffect برای فراخوانی یک API در زمان بارگذاری اولیه صفحه استفاده می‌شود و داده‌ها در state ذخیره می‌شوند.

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

function DataFetcher() {
  const [data, setData] = useState([]);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then((response) => response.json())
      .then((data) => setData(data));

    // بدون آرایه وابستگی، این effect فقط یک بار در بارگذاری اولیه اجرا می‌شود.
  }, []);

  return (
    <ul>
      {data.map((item) => (
        <li key={item.id}>{item.title}</li>
      ))}
    </ul>
  );
}

در این مثال:

useEffect بدون وابستگی اجرا شده است، بنابراین تنها یک بار در بارگذاری اولیه کامپوننت اجرا می‌شود.
fetch برای دریافت داده‌ها از API استفاده شده و داده‌ها در state ذخیره می‌شوند.
مثال: تنظیم تایمر با استفاده از useEffect
در مثال زیر، یک تایمر با setInterval تنظیم شده که هر ثانیه state شمارنده را افزایش می‌دهد. همچنین، تابع پاک‌سازی تایمر را در زمان حذف کامپوننت متوقف می‌کند.

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

function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => setCount((prev) => prev + 1), 1000);

    return () => clearInterval(interval); // پاک‌سازی تایمر در زمان حذف کامپوننت
  }, []);

  return <div>Time: {count}s</div>;
}

در این مثال:

تایمر هر ثانیه اجرا شده و مقدار state count افزایش می‌یابد.
تابع clearInterval برای پاک‌سازی تایمر در زمان حذف کامپوننت استفاده شده است.
پاک‌سازی منابع با استفاده از useEffect
یکی از ویژگی‌های مهم useEffect قابلیت تعریف تابع بازگشتی برای پاک‌سازی منابع است. این تابع هنگام حذف کامپوننت یا تغییر وابستگی‌ها اجرا می‌شود.

مثال: ثبت و حذف event listener با استفاده از useEffect
در مثال زیر، از useEffect برای ثبت یک event listener استفاده شده که اندازه پنجره مرورگر را ثبت می‌کند و در هنگام حذف کامپوننت یا تغییر وابستگی‌ها، این listener پاک‌سازی می‌شود.

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

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

  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);

    window.addEventListener('resize', handleResize);

    // پاک‌سازی در زمان حذف کامپوننت
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return <div>Window width: {width}px</div>;
}

در این مثال:

هر بار که اندازه پنجره تغییر می‌کند، مقدار state width به‌روزرسانی می‌شود.
با removeEventListener، listener ثبت‌شده پاک‌سازی می‌شود.

نکات مهم در استفاده از useEffect

آرایه وابستگی‌ها (Dependency Array): اگر از آرایه وابستگی‌ها استفاده نکنید، useEffect در هر بار رندر اجرا می‌شود که ممکن است منجر به مشکلات عملکردی شود. استفاده صحیح از آرایه وابستگی‌ها، به بهینه‌سازی و کاهش تعداد اجرای useEffect کمک می‌کند.

پاک‌سازی منابع: همیشه به یاد داشته باشید که برای منابعی مانند تایمرها یا event listeners، تابع پاک‌سازی را تعریف کنید تا از مشکلاتی مانند memory leak جلوگیری شود.

وابستگی‌های پویا: اگر متغیرهایی دارید که درون useEffect استفاده می‌شوند، حتماً آن‌ها را در آرایه وابستگی‌ها قرار دهید. این کار از مشکلات احتمالی مربوط به نوسازی داده‌ها و ناهمگام بودن state جلوگیری می‌کند. useEffect یکی از قدرتمندترین و مهم‌ترین Hooks React است که به توسعه‌دهندگان امکان می‌دهد عملیات‌های جانبی را به سادگی و با انعطاف‌پذیری بالا مدیریت کنند. با درک صحیح و استفاده مناسب از useEffect، می‌توانید منطق خود را به خوبی در اجزای توابعی به کار گیرید و قابلیت‌های پیچیده‌ای مانند فراخوانی API، مدیریت تایمرها، و تنظیم و پاک‌سازی منابع را به پروژه‌های React خود اضافه کنید.

قوانین Hook‌ها

React Hooks به توسعه‌دهندگان این امکان را می‌دهند که قابلیت‌های پیشرفته‌ای همچون state و چرخه عمر (Lifecycle) را در اجزای توابعی استفاده کنند، اما برای استفاده از آن‌ها نیاز است که دو قانون کلیدی و مهم را رعایت کنید. این قوانین توسط تیم توسعه React به منظور جلوگیری از بروز رفتارهای غیرمنتظره و مشکلات در کارکرد صحیح کامپوننت‌ها معرفی شده‌اند.

۱. فقط در بالاترین سطح کدهای تابع از Hook استفاده کنید

این قانون به این معناست که شما باید Hooks را در سطح بالای تابع اجزا (Component) تعریف کنید و نباید آن‌ها را درون حلقه‌ها، شرایط (if/else) یا توابع تو در تو (nested functions) قرار دهید. این محدودیت به React کمک می‌کند که ترتیب Hooks را در هر رندر به طور دقیق حفظ کند و مطمئن شود که stateها و اثرات به درستی اعمال و پیگیری می‌شوند.

چرا باید از این قانون پیروی کنیم؟

React به ترتیب اجرای Hooks در طول هر رندر وابسته است. اگر Hooks در شرایط مختلف یا در حلقه‌ها قرار بگیرند، ترتیب اجرا ممکن است تغییر کند و این موضوع منجر به خطاهای مختلفی در state و اثرات خواهد شد. پیروی از این قانون به React این امکان را می‌دهد که هر Hook را به یک محل خاص نسبت دهد و مطمئن شود که مقادیر صحیح در هر رندر بازگردانده می‌شوند.

مثال اشتباه
در این مثال، useEffect به صورت شرطی فراخوانی شده است که خلاف این قانون است.

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

function Example() {
  const [count, setCount] = useState(0);

  // اشتباه: فراخوانی useEffect به صورت شرطی
  if (count > 5) {
    useEffect(() => {
      console.log('Count is greater than 5');
    });
  }

  return <button onClick={() => setCount(count + 1)}>Increase</button>;
}

مثال صحیح
به جای قرار دادن useEffect در یک شرط، می‌توان آن را به صورتی تعریف کرد که به state count واکنش نشان دهد، بدون این که درون شرط یا حلقه قرار گیرد:

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

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    if (count > 5) {
      console.log('Count is greater than 5');
    }
  }, [count]);

  return <button onClick={() => setCount(count + 1)}>Increase</button>;
}

در این حالت، useEffect همیشه اجرا می‌شود و تنها زمانی که count تغییر کند، شرط داخلی آن اجرا می‌شود.

۲. فقط در اجزای توابعی و Hook‌های سفارشی از Hook‌ها استفاده کنید

Hooks را فقط درون اجزای توابعی React یا Hook‌های سفارشی (Custom Hooks) تعریف کنید. این قانون به این معناست که شما نباید از Hooks درون توابع معمولی جاوااسکریپت، کلاس‌ها، یا حتی توابع کمکی استفاده کنید.

چرا باید از این قانون پیروی کنیم؟

Hooks در داخل اجزای توابعی React و Hook‌های سفارشی طراحی شده‌اند تا به React کمک کنند تا state و چرخه عمر را به درستی مدیریت کند. خارج از این محیط‌ها، React نمی‌تواند ترتیبی برای این Hooks تعریف کند و بنابراین پیگیری و مدیریت آن‌ها غیرممکن یا پیچیده می‌شود. استفاده از Hooks در خارج از این محدوده می‌تواند منجر به خطاهای غیرقابل پیش‌بینی شود.

مثال اشتباه
در این مثال، useState به صورت نادرستی در یک تابع کمکی استفاده شده است:

import React, { useState } from 'react';

function incrementCounter() {
  const [count, setCount] = useState(0); // اشتباه: استفاده از useState در تابع کمکی
  setCount(count + 1);
}

function Counter() {
  return (
    <button onClick={incrementCounter}>Increase</button>
  );
}

در این مثال، useState در یک تابع جداگانه و خارج از کامپوننت اصلی استفاده شده است، که موجب می‌شود React نتواند آن را به درستی پیگیری کند.

مثال صحیح
در عوض، useState را مستقیماً درون کامپوننت اصلی تعریف می‌کنیم:

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const incrementCounter = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={incrementCounter}>Increase</button>
    </div>
  );
}

در این مثال، useState به درستی در کامپوننت Counter تعریف شده و تابع incrementCounter از داخل کامپوننت اصلی به آن دسترسی دارد.

رعایت قوانین Hook‌ها در Hook‌های سفارشی

هنگام ایجاد Hook‌های سفارشی (Custom Hooks) که برای استخراج و اشتراک‌گذاری منطق استفاده می‌شوند، این قوانین همچنان پابرجا هستند. Hook‌های سفارشی باید به طور کامل به قوانین Hooks پایبند باشند، به این معنی که:

نباید در شرایط، حلقه‌ها، یا توابع تو در تو قرار گیرند.
تنها درون کامپوننت‌ها یا Hook‌های سفارشی دیگر استفاده شوند.
مثال: ساخت یک Hook سفارشی برای مدیریت شمارنده
در این مثال، یک Hook سفارشی به نام useCounter ایجاد شده که state شمارنده را مدیریت می‌کند. این Hook همچنان به قوانین Hooks پایبند است.

import { useState } from 'react';

function useCounter(initialValue = 0) {
  const [count, setCount] = useState(initialValue);

  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);

  return { count, increment, decrement };
}

export default useCounter;

می‌توانید از این Hook سفارشی در یک کامپوننت به صورت زیر استفاده کنید:

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

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increase</button>
      <button onClick={decrement}>Decrease</button>
    </div>
  );
}

در این مثال، useCounter به عنوان یک Hook سفارشی، قوانین Hooks را رعایت کرده است و تنها در سطح بالای تابع کامپوننت CounterComponent فراخوانی می‌شود.رعایت قوانین Hooks React از اهمیت زیادی برخوردار است و کمک می‌کند که React بتواند state و چرخه عمر را به درستی مدیریت کند. پیروی از این قوانین، از بروز خطاهای غیرمنتظره جلوگیری کرده و تضمین می‌کند که Hooks به درستی و به صورت پیش‌بینی‌پذیر عمل کنند.

استفاده از useContext

useContext یکی از React Hooks بسیار کاربردی است که به شما اجازه می‌دهد به داده‌های یک Context به سادگی دسترسی پیدا کنید، بدون اینکه نیازی به استفاده از Context.Consumer یا ارسال داده‌ها به صورت props داشته باشید. Context در React برای اشتراک‌گذاری داده‌هایی مانند تم (theme)، زبان، و داده‌های کاربری میان اجزا مختلف و در سطح‌های مختلف درخت کامپوننت استفاده می‌شود، بدون اینکه نیاز باشد آن داده‌ها را در هر سطح به صورت props ارسال کنید.

معرفی Context و استفاده از useContext

Context در React به شما امکان می‌دهد داده‌ها را در سطح بالای درخت اجزا (مثل سطح App) تعریف کنید و سپس این داده‌ها را در سطح‌های پایین‌تر به طور مستقیم مورد استفاده قرار دهید. useContext این کار را با سادگی بیشتری انجام می‌دهد و به شما اجازه می‌دهد مستقیماً به مقدار Context دسترسی داشته باشید، در حالی که نیازی به پیچیدگی‌های Context.Consumer در اجزای توابعی ندارید.

سینتکس استفاده از useContext

const value = useContext(MyContext);

MyContext نام Contextی است که قبلاً با استفاده از React.createContext ایجاد کرده‌اید.
value مقدار Context است که در حال حاضر در دسترس است و می‌توانید از آن در اجزای مختلف استفاده کنید.

نحوه ایجاد و استفاده از Context

برای استفاده از useContext، ابتدا باید یک Context ایجاد کنید. این کار با استفاده از React.createContext انجام می‌شود که به Context مقدار پیش‌فرضی اختصاص می‌دهد. سپس می‌توانید useContext را برای دسترسی به مقدار Context در کامپوننت‌های فرزند استفاده کنید.

مراحل کلی:
ایجاد Context با مقدار پیش‌فرض (اختیاری).
استفاده از Provider برای تعریف مقداری که می‌خواهید به اجزای فرزند ارسال کنید.
استفاده از useContext برای دسترسی به مقدار Context در هر جایی از درخت کامپوننت.

مثال: ایجاد یک Context برای تم (Theme)

در مثال زیر، یک Context برای تم (theme) ایجاد کرده‌ایم و از useContext برای دسترسی به مقدار آن در یک دکمه استفاده می‌کنیم.

import React, { useContext } from 'react';

// ایجاد ThemeContext با مقدار پیش‌فرض "light"
const ThemeContext = React.createContext('light');

function ThemedButton() {
  // استفاده از useContext برای دسترسی به مقدار Context
  const theme = useContext(ThemeContext);

  return <button className={theme}>Themed Button</button>;
}

function App() {
  return (
    // استفاده از ThemeContext.Provider برای تعریف مقدار "dark"
    <ThemeContext.Provider value="dark">
      <ThemedButton />
    </ThemeContext.Provider>
  );
}

export default App;

در این مثال:

ThemeContext با مقدار پیش‌فرض “light” ایجاد شده است.
ThemeContext.Provider در سطح بالای درخت (در کامپوننت App) استفاده شده و مقدار “dark” را به عنوان مقدار Context فراهم می‌کند.
کامپوننت ThemedButton با استفاده از useContext به مقدار Context دسترسی پیدا می‌کند و مقدار theme را به عنوان کلاس دکمه اعمال می‌کند.

مزایای استفاده از useContext در مقابل Context.Consumer

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

مزایای استفاده از useContext

کاهش پیچیدگی کد: استفاده از useContext نیازی به تعریف Context.Consumer و استفاده از توابع درون توابع را ندارد.
خوانایی بهتر: useContext کدی ساده‌تر و خواناتر ایجاد می‌کند، مخصوصاً زمانی که از چندین Context استفاده می‌کنید.
کاهش وابستگی به Props Drilling: useContext به اجزا اجازه می‌دهد مستقیماً به مقدار Context دسترسی داشته باشند، بدون نیاز به ارسال داده‌ها از طریق props در سطوح مختلف درخت کامپوننت.

مثال کاربردی: مدیریت کاربر وارد شده با استفاده از Context

در این مثال، از Context برای مدیریت اطلاعات کاربر وارد شده (مانند نام کاربری) استفاده می‌شود. این اطلاعات در سطح بالای درخت کامپوننت‌ها تعریف شده و سپس با استفاده از useContext در کامپوننت‌های فرزند دسترسی‌پذیر می‌شود.

import React, { useContext, useState } from 'react';

// ایجاد UserContext
const UserContext = React.createContext();

function UserInfo() {
  const user = useContext(UserContext);
  return <h2>Welcome, {user.name}!</h2>;
}

function App() {
  const [user] = useState({ name: 'Ali', email: 'ali@example.com' });

  return (
    // فراهم کردن مقدار UserContext با استفاده از Provider
    <UserContext.Provider value={user}>
      <UserInfo />
    </UserContext.Provider>
  );
}

export default App;

در این مثال:

UserContext برای مدیریت اطلاعات کاربر ایجاد شده است.
UserContext.Provider مقدار user را به عنوان Context فراهم می‌کند.
UserInfo با استفاده از useContext به اطلاعات کاربر دسترسی پیدا می‌کند و نام کاربر را نمایش می‌دهد.

نکات مهم هنگام استفاده از useContext

Context باید در سطح بالای درخت تعریف شود: مقدار Context باید در یک سطح بالا با استفاده از Provider تعیین شود تا تمام اجزای فرزند به آن دسترسی داشته باشند.
ارزش‌های پویا: اگر مقداری که به Provider می‌دهید به طور پویا تغییر می‌کند، مانند state، می‌توانید از useState یا useReducer استفاده کنید تا مقدار Context را مدیریت کنید.
Context‌های متعدد: در پروژه‌های بزرگ ممکن است نیاز به استفاده از چندین Context داشته باشید. برای استفاده از چندین Context، می‌توانید چندین useContext را به صورت جداگانه در یک کامپوننت فراخوانی کنید. useContext یکی از React Hooks قدرتمند و مفید است که استفاده از Context را در اجزای توابعی آسان می‌کند و نیاز به استفاده از Context.Consumer را از بین می‌برد. با استفاده از useContext می‌توانید داده‌ها را به سادگی و بدون نیاز به ارسال آن‌ها از طریق props در بین سطوح مختلف درخت کامپوننت به اشتراک بگذارید، که این امر باعث کاهش پیچیدگی کد و بهبود خوانایی آن می‌شود.

استفاده از useReducer

useReducer یکی از Hooks React است که برای مدیریت وضعیت (state) پیچیده‌تر و منطق‌های چند مرحله‌ای در اجزای توابعی (Functional Components) طراحی شده است. در حالی که useState برای مدیریت stateهای ساده و مستقیم ایده‌آل است، useReducer برای مواقعی که چندین مقدار state با هم در تعامل هستند و منطق به‌روزرسانی آن‌ها پیچیده‌تر است، کاربرد بهتری دارد. این Hook رویکردی مشابه به الگوی Redux دارد و بر اساس مفهوم reducer عمل می‌کند.

نحوه کار useReducer

useReducer با دریافت دو آرگومان عمل می‌کند:

تابع reducer: این تابع منطق به‌روزرسانی state را بر اساس نوع action تعیین می‌کند. این تابع دو پارامتر دارد:

state: وضعیت کنونی
action: شیءای که نوع و داده‌های لازم برای به‌روزرسانی state را دارد
مقدار اولیه state: مقدار اولیه که state با آن شروع به کار می‌کند.

خروجی useReducer یک آرایه دو عضوی است:

state: وضعیت فعلی
dispatch: تابعی برای ارسال action‌ها به reducer برای به‌روزرسانی state
سینتکس

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

چرا از useReducer استفاده کنیم؟

useReducer در شرایطی مناسب است که:

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

مثال: شمارنده با استفاده از useReducer

در این مثال، useReducer برای مدیریت شمارنده‌ای استفاده شده که با دکمه‌ها افزایش و کاهش می‌یابد. تابع reducer منطق تغییر state را بر اساس نوع action (increment و decrement) مشخص می‌کند.

import React, { useReducer } from 'react';

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

function Counter() {
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
}

در این مثال:

counterReducer منطق state را مدیریت می‌کند و با توجه به نوع action (increment یا decrement) مقدار شمارنده را به‌روزرسانی می‌کند.
dispatch برای ارسال action استفاده می‌شود. هر بار که یک action ارسال می‌شود، useReducer تابع reducer را با state و action جدید فراخوانی می‌کند و state به‌روزرسانی می‌شود.

ساختار تابع reducer

تابع reducer نقش اصلی در useReducer را ایفا می‌کند و منطق تغییر state را مدیریت می‌کند. این تابع باید بر اساس نوع action (مشخص شده با action.type) تصمیم بگیرد که چگونه state را به‌روزرسانی کند.

function reducer(state, action) {
  switch (action.type) {
    case 'ACTION_TYPE_1':
      return { ...state, property: newValue };
    case 'ACTION_TYPE_2':
      return { ...state, anotherProperty: anotherValue };
    default:
      return state;
  }
}

مثال کاربردی: فرم با استفاده از useReducer

در این مثال، از useReducer برای مدیریت یک فرم ساده استفاده شده که شامل نام و ایمیل است. تابع reducer مسئول به‌روزرسانی state به ازای هر تغییر در فیلدهای فرم است.

import React, { useReducer } from 'react';

const initialState = { name: '', email: '' };

function formReducer(state, action) {
  switch (action.type) {
    case 'SET_NAME':
      return { ...state, name: action.payload };
    case 'SET_EMAIL':
      return { ...state, email: action.payload };
    default:
      throw new Error('Unknown action type');
  }
}

function Form() {
  const [state, dispatch] = useReducer(formReducer, initialState);

  const handleNameChange = (e) => {
    dispatch({ type: 'SET_NAME', payload: e.target.value });
  };

  const handleEmailChange = (e) => {
    dispatch({ type: 'SET_EMAIL', payload: e.target.value });
  };

  return (
    <form>
      <input
        type="text"
        value={state.name}
        onChange={handleNameChange}
        placeholder="Name"
      />
      <input
        type="email"
        value={state.email}
        onChange={handleEmailChange}
        placeholder="Email"
      />
      <p>Name: {state.name}</p>
      <p>Email: {state.email}</p>
    </form>
  );
}

export default Form;

در این مثال:

initialState مقدار اولیه state فرم را تعریف می‌کند.
formReducer به ازای هر action که نوع و payload دارد، state را به‌روزرسانی می‌کند.
dispatch برای تغییر مقدار state با ارسال نوع action (SET_NAME یا SET_EMAIL) و مقدار جدید (payload) استفاده می‌شود.

نکات مهم در استفاده از useReducer

مناسب برای وضعیت‌های پیچیده‌تر: useReducer برای زمانی مناسب است که state شامل چندین مقدار وابسته باشد که تغییرات آن‌ها نیاز به منطق خاصی دارد.

حفظ تاریخچه تغییرات: با استفاده از useReducer، می‌توانید تغییرات را به طور دقیق پیگیری کنید. این ویژگی زمانی که از Redux استفاده نمی‌کنید، می‌تواند مفید باشد.

بهبود خوانایی کد: با استفاده از تابع reducer، منطق به‌روزرسانی state از کد کامپوننت جدا شده و ساختار کد ساده‌تر و خواناتر می‌شود.

انعطاف‌پذیری در ساختار actionها: می‌توانید action‌هایی با ساختار دلخواه خود ایجاد کنید که شامل داده‌های مختلف باشند. این کار به مدیریت بهینه‌تر state کمک می‌کند.useReducer یکی از Hooks React پرکاربرد برای مدیریت state‌های پیچیده و چند مرحله‌ای است. این Hook در شرایطی که استفاده از useState منجر به کد پیچیده و سخت‌فهم می‌شود، جایگزین مناسبی است. با استفاده از useReducer، می‌توانید منطق‌های پیچیده به‌روزرسانی state را در یک تابع مجزا مدیریت کنید، که به سادگی و بهینه‌سازی کد شما کمک می‌کند.

استفاده از useMemo و useCallback

useMemo و useCallback از Hooks React هستند که برای بهینه‌سازی عملکرد اجزای توابعی (Functional Components) به کار می‌روند. این دو Hook به شما اجازه می‌دهند که از محاسبات و بازگشت‌های غیرضروری جلوگیری کرده و عملکرد کد خود را بهبود بخشید.

useMemo: از این Hook برای بازگرداندن یک مقدار محاسبه شده (مانند نتیجه محاسبات سنگین یا پیچیده) استفاده می‌شود. با استفاده از useMemo، می‌توانید تعیین کنید که یک محاسبه فقط زمانی انجام شود که مقادیر خاصی تغییر کنند.
useCallback: این Hook برای بازگشت یک تابع حافظه‌شده (Memoized Function) استفاده می‌شود. useCallback باعث می‌شود که یک تابع تنها زمانی بازسازی شود که وابستگی‌های مشخصی تغییر کنند. این امر از ایجاد توابع جدید در هر رندر جلوگیری می‌کند و بهینه‌سازی عملکرد را به دنبال دارد.

استفاده از useMemo

useMemo به شما اجازه می‌دهد تا نتیجه یک محاسبه را بر اساس وابستگی‌های مشخص تنها زمانی که این وابستگی‌ها تغییر می‌کنند، محاسبه و ذخیره کنید. به این ترتیب، محاسبات سنگین و غیرضروری در هر رندر مجدد انجام نمی‌شوند.

سینتکس

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

تابع محاسباتی: تابعی که نتیجه محاسبات را باز می‌گرداند.
آرایه وابستگی‌ها: مقادیری که هرگاه تغییر کنند، باعث اجرای مجدد محاسبه می‌شوند.

مثال: بهینه‌سازی محاسبات سنگین با useMemo

در مثال زیر، useMemo برای محاسبه یک نتیجه سنگین استفاده شده است. این نتیجه تنها زمانی محاسبه می‌شود که مقدار count تغییر کند.

import React, { useState, useMemo } from 'react';

function ExpensiveCalculation() {
  const [count, setCount] = useState(0);

  const expensiveResult = useMemo(() => {
    console.log("Calculating...");
    return count * 2;
  }, [count]);

  return (
    <div>
      <p>Expensive Result: {expensiveResult}</p>
      <button onClick={() => setCount(count + 1)}>Increase</button>
    </div>
  );
}

export default ExpensiveCalculation;

در این مثال:

useMemo باعث می‌شود که محاسبه count * 2 تنها در صورتی که count تغییر کند، انجام شود.
اگر سایر stateها تغییر کنند ولی count ثابت بماند، محاسبه مجدداً انجام نمی‌شود و از مقدار ذخیره‌شده قبلی استفاده می‌شود.

استفاده از useCallback

useCallback به شما اجازه می‌دهد که توابعی را که در هر رندر مجدداً ساخته می‌شوند، بهینه کنید. این Hook به ویژه در مواردی کاربرد دارد که تابعی به عنوان props به یک کامپوننت فرزند ارسال می‌شود و تغییر نکردن آن تابع می‌تواند از رندرهای غیرضروری فرزند جلوگیری کند.

سینتکس

const memoizedCallback = useCallback(() => {
  // تابعی که نیاز به حافظه‌شدن دارد
}, [dependencies]);

تابع: تابعی که می‌خواهید حافظه‌شده باشد.
آرایه وابستگی‌ها: تابع تنها زمانی که این مقادیر تغییر کنند، بازسازی می‌شود.

مثال: بهینه‌سازی توابع با استفاده از useCallback

در مثال زیر، از useCallback برای جلوگیری از بازسازی تابع handleClick در هر رندر استفاده شده است.

import React, { useState, useCallback } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increase</button>
    </div>
  );
}

export default Counter;

در این مثال:

useCallback تضمین می‌کند که handleClick تنها زمانی که مقدار count تغییر کند، بازسازی شود.
در نتیجه، اگر props دیگری تغییر کند، این تابع همان نسخه قبلی باقی می‌ماند و از تغییرات غیرضروری جلوگیری می‌شود.

کاربردهای متداول useMemo و useCallback

محاسبات سنگین: اگر تابعی نیاز به محاسبات سنگین دارد و این محاسبات فقط بر اساس چند مقدار خاص تغییر می‌کنند، useMemo انتخاب مناسبی است.
بهینه‌سازی توابع در کامپوننت‌های فرزند: اگر تابعی را به عنوان props به کامپوننت فرزند ارسال می‌کنید و می‌خواهید این تابع تنها در صورت تغییر وابستگی‌ها بازسازی شود، useCallback مفید است.
پیشگیری از رندرهای غیرضروری: useMemo و useCallback به شما کمک می‌کنند تا از بازسازی‌های غیرضروری کامپوننت‌ها و رندرهای اضافی جلوگیری کنید، که به بهینه‌سازی عملکرد کمک می‌کند.

تفاوت بین useMemo و useCallback

useMemo مقدار محاسبه‌شده را بازمی‌گرداند، در حالی که useCallback یک تابع حافظه‌شده را بازمی‌گرداند.
useMemo برای زمانی که به نتیجه محاسبات نیاز دارید مناسب است، در حالی که useCallback برای بهینه‌سازی توابعی که به عنوان props به کامپوننت‌های فرزند ارسال می‌شوند، مناسب‌تر است.
نکات مهم
بیش از حد استفاده نکنید: از useMemo و useCallback تنها زمانی که عملکرد دچار مشکل است، استفاده کنید. در غیر این صورت، ممکن است پیچیدگی غیرضروری به کد اضافه شود.
وابستگی‌ها را به درستی مشخص کنید: همیشه مطمئن شوید که آرایه وابستگی‌ها شامل تمامی مقادیری است که تابع یا مقدار حافظه‌شده به آن‌ها وابسته است.
حافظه‌ی توابع: استفاده‌ی بیش از حد از useCallback می‌تواند به مصرف زیاد حافظه منجر شود، چرا که توابع در حافظه نگهداری می‌شوند.

useMemo و useCallback از Hooks React هستند که به شما کمک می‌کنند عملکرد برنامه خود را با جلوگیری از محاسبات و توابع غیرضروری بهینه‌سازی کنید. useMemo برای بازگرداندن مقادیر محاسباتی استفاده می‌شود و useCallback برای بازگرداندن توابع حافظه‌شده که تغییر نمی‌کنند، کاربرد دارد. این Hooks زمانی که به درستی و در شرایط مناسب استفاده شوند، می‌توانند بهبود قابل توجهی در عملکرد برنامه‌های React ایجاد کنند.

ساخت Hook‌های سفارشی

Hook‌های سفارشی (Custom Hooks) در React به شما امکان می‌دهند که منطق متداول و تکراری را در یک تابع مجزا استخراج کرده و در بین اجزای مختلف به اشتراک بگذارید. این رویکرد به شما کمک می‌کند که کدهای خود را ماژولار، خوانا و قابل نگهداری‌تر کنید. Hook‌های سفارشی به طور ویژه برای زمانی مفید هستند که نیاز به استفاده از stateها و Hooks مشابه در بخش‌های مختلف برنامه دارید، مانند مدیریت داده‌ها، تعاملات API، و ذخیره اطلاعات ورودی کاربر.

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

ساخت Hook‌های سفارشی به شما اجازه می‌دهد که کدهای تکراری را در یک مکان واحد قرار داده و از آن در بخش‌های مختلف برنامه استفاده کنید. مزایای اصلی استفاده از Hook‌های سفارشی عبارتند از:

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

نحوه ساخت یک Hook سفارشی

برای ساخت یک Hook سفارشی:

از use در ابتدای نام آن استفاده کنید (مانند useFetch، useCounter و غیره).
منطق موردنظر را با استفاده از stateها و Hooks استاندارد تعریف کنید.
مقادیری که می‌خواهید به کامپوننت‌ها برگردانید را با استفاده از return به عنوان خروجی ارائه دهید.
مثال: ساخت یک Hook سفارشی برای دریافت داده‌ها با useFetch
در مثال زیر، یک Hook سفارشی به نام useFetch ساخته شده که برای دریافت داده‌ها از یک URL مشخص استفاده می‌شود.

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch(url)
      .then((response) => response.json())
      .then((data) => {
        setData(data);
        setLoading(false);
      });
  }, [url]);

  return { data, loading };
}

export default useFetch;

در این مثال:

useFetch دو state به نام‌های data و loading ایجاد می‌کند تا وضعیت دریافت داده‌ها را مدیریت کند.
از useEffect برای فراخوانی fetch در زمان بارگذاری اولیه یا هر زمان که url تغییر کند، استفاده شده است.
این Hook سفارشی دو مقدار data و loading را بازمی‌گرداند تا در کامپوننت‌هایی که از آن استفاده می‌کنند، دسترسی‌پذیر باشد.

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

در کد زیر، از useFetch برای دریافت و نمایش داده‌ها در یک کامپوننت استفاده شده است:

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

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

  if (loading) return <p>Loading...</p>;

  return (
    <ul>
      {data.map((item) => (
        <li key={item.id}>{item.title}</li>
      ))}
    </ul>
  );
}

export default DataDisplay;

ساخت Hook‌های سفارشی پیچیده‌تر

می‌توانید Hook‌های سفارشی پیچیده‌تری بسازید که به چندین state، Hooks یا حتی Hooks سفارشی دیگر وابسته باشند. به عنوان مثال، یک Hook سفارشی برای مدیریت ورودی‌های فرم که اعتبارسنجی داده‌ها را هم در بر گیرد، می‌تواند به این شکل ساخته شود.

مثال: Hook سفارشی برای مدیریت ورودی فرم

import { useState } from 'react';

function useForm(initialValues) {
  const [values, setValues] = useState(initialValues);

  const handleChange = (e) => {
    const { name, value } = e.target;
    setValues({
      ...values,
      [name]: value,
    });
  };

  const resetForm = () => {
    setValues(initialValues);
  };

  return { values, handleChange, resetForm };
}

export default useForm;

در این مثال:

useForm state ورودی‌های فرم را نگه می‌دارد و یک تابع handleChange برای به‌روزرسانی آن‌ها و یک تابع resetForm برای بازنشانی فرم ایجاد می‌کند.
این Hook سفارشی برای استفاده مجدد در فرم‌های مختلف طراحی شده است.

استفاده از useForm در یک فرم

در کد زیر، از useForm برای مدیریت ورودی‌های یک فرم ساده استفاده شده است:

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

function UserForm() {
  const { values, handleChange, resetForm } = useForm({ name: '', email: '' });

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(values);
    resetForm();
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        name="name"
        value={values.name}
        onChange={handleChange}
        placeholder="Name"
      />
      <input
        type="email"
        name="email"
        value={values.email}
        onChange={handleChange}
        placeholder="Email"
      />
      <button type="submit">Submit</button>
    </form>
  );
}

export default UserForm;

 

نکات مهم در ساخت Hook‌های سفارشی

استفاده از نام‌گذاری صحیح: نام Hook‌های سفارشی باید با use شروع شود تا React بتواند آن‌ها را به عنوان Hooks شناسایی کند.
بازگشت مقادیر موردنیاز: تنها مقادیر و توابعی که نیاز است در دسترس کامپوننت‌های استفاده‌کننده قرار بگیرد را بازگردانید.
استفاده مجدد: سعی کنید Hook‌های سفارشی را به گونه‌ای طراحی کنید که در کامپوننت‌های مختلف قابل استفاده مجدد باشند.
رعایت قوانین Hooks: Hook‌های سفارشی نیز باید از قوانین Hooks پیروی کنند، یعنی باید در بالاترین سطح تعریف شوند و نباید درون شرایط یا حلقه‌ها قرار گیرند.
Hook‌های سفارشی یکی از قدرتمندترین امکانات React هستند که به شما اجازه می‌دهند منطق‌های متداول و تکراری را به صورت کپسوله‌شده در یک تابع جداگانه قرار دهید و آن را در کامپوننت‌های مختلف به اشتراک بگذارید. این قابلیت باعث می‌شود کد شما خواناتر، ماژولارتر و قابل نگهداری‌تر باشد.

نتیجه‌گیری

Hooks React ابزارهای قدرتمندی هستند که به توسعه‌دهندگان امکان می‌دهند از ویژگی‌های پیشرفته‌ای مانند state، چرخه عمر، و بهینه‌سازی عملکرد بدون نیاز به کلاس‌ها در اجزای توابعی استفاده کنند. با useState می‌توانید وضعیت‌های ساده را مدیریت کنید و با useEffect به راحتی به تغییرات state و props واکنش نشان دهید. در مواردی که وضعیت‌های پیچیده‌تری نیاز است، useReducer جایگزین مناسبی برای مدیریت منطق‌های پیچیده و چندمرحله‌ای است. useMemo و useCallback ابزارهایی برای بهینه‌سازی عملکرد هستند که از محاسبات و توابع غیرضروری جلوگیری می‌کنند، و useContext امکان اشتراک‌گذاری داده‌ها را بدون نیاز به props فراهم می‌کند.

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

آموزش Hooks React

دیدگاه های شما

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *