آموزش استفاده از هوک ها (Hooks) در ReactJS: از مبانی تا پیشرفته

آموزش استفاده از هوک ها (Hooks) در ReactJS: از مبانی تا پیشرفته

جادوگری با هوک ها در React : از صفر تا صد!

یادتونه روزایی که برای مدیریت state و lifecycle کامپوننت ها توی React باید کلی کلاس می نوشتیم و با this و bind و هزار تا چیز دیگه کلنجار می رفتیم؟ خب اون روزا دیگه تقریباً تموم شده! React Hooks اومدن تا زندگی رو برای ما دولوپرها خیلی آسون تر کنن. فکر کنین بتونین تمام قدرت های کامپوننت های کلاسی رو ولی توی کامپوننت های فانکشنال داشته باشید. جذاب نیست؟

هوک ها مثل ابرقهرمان های دنیای React هستن هر کدوم یه قابلیت خاص دارن و با ترکیبشون می تونیم کدهای خیلی تمیزتر و قابل فهم تری بنویسیم. توی این مقاله می خوایم با هم سفر کنیم به دنیای هوک ها از مباحث پایه شروع کنیم و کم کم برسیم به تکنیک های پیشرفته. پس کمربندها رو ببندید چون قراره کلی چیز جدید یاد بگیریم!

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

بذارید اول از همه یه تعریف ساده از هوک ها داشته باشیم. هوک ها توابع جاوااسکریپتی هستن که به ما اجازه می دن از state و ویژگی های lifecycle در کامپوننت های فانکشنال React استفاده کنیم. یعنی چی؟ یعنی دیگه لازم نیست برای استفاده از state یا lifecycle به کامپوننت های کلاسی پناه ببریم! هوک ها اومدن تا کدنویسی React رو ساده تر خواناتر و قابل استفاده مجددتر کنن.

خب چرا باید از هوک ها استفاده کنیم؟ دلایل خیلی خوبی برای آموزش ری اکت و استفاده از هوک ها وجود داره :

  1. کد کمتر خوانایی بیشتر : هوک ها باعث می شن کد کامپوننت ها خیلی خلاصه تر و تمیزتر بشه. دیگه لازم نیست با پیچیدگی های کامپوننت های کلاسی مثل this و lifecycle methods دست و پنجه نرم کنید. کد فانکشنال با هوک ها معمولاً خیلی سرراست تر و قابل فهم تره.
  2. استفاده مجدد از منطق Stateful : یکی از بزرگترین مزایای هوک ها امکان استفاده مجدد از منطق stateful بین کامپوننت هاست. قبلاً برای این کار باید از HOCها (Higher-Order Components) یا render props استفاده می کردیم که گاهی اوقات پیچیده و گیج کننده می شدن. هوک های سفارشی (Custom Hooks) این مشکل رو به راحتی حل می کنن.
  3. سازماندهی بهتر کامپوننت ها : هوک ها کمک می کنن تا منطق مربوط به state و side effects رو به صورت منطقی تر و سازمان یافته تر توی کامپوننت ها مدیریت کنیم. به جای اینکه تمام منطق رو توی lifecycle methods پراکنده کنیم می تونیم با استفاده از هوک ها هر بخش از منطق رو جداگانه مدیریت کنیم.
  4. تست پذیری راحت تر : کامپوننت های فانکشنال با هوک ها معمولاً تست پذیرتر از کامپوننت های کلاسی هستن. به خاطر ساختار ساده تر و جداسازی منطق تست کردن هوک ها و کامپوننت هایی که ازشون استفاده می کنن خیلی راحت تره.
  5. جامعه بزرگ و پشتیبانی قوی : هوک ها از سال ۲۰۱۹ به React اضافه شدن و از اون موقع به بعد جامعه React به شدت ازشون استقبال کرده. منابع آموزشی زیادی در مورد هوک ها وجود داره و اگه به مشکلی برخوردید به احتمال زیاد جوابش رو به راحتی پیدا می کنید.

به طور خلاصه هوک ها یه ابزار قدرتمند هستن که کدنویسی React رو لذت بخش تر و کارآمدتر می کنن. اگه هنوز با هوک ها آشنا نیستید پیشنهاد می کنم حتماً شروع به یادگیریشون کنید. مطمئنم عاشقشون می شید!

آموزش استفاده از هوک ها (Hooks) در ReactJS: از مبانی تا پیشرفته

useState : جادوی مدیریت State در کامپوننت های فانکشنال

اولین و یکی از پرکاربردترین هوک ها useState هست. این هوک به ما اجازه می ده تا state رو توی کامپوننت های فانکشنال تعریف و مدیریت کنیم. قبل از هوک ها فقط کامپوننت های کلاسی می تونستن state داشته باشن ولی حالا با useState کامپوننت های فانکشنال هم می تونن stateful باشن. عالیه نه؟

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

useState یه هوکه که یه جفت مقدار برمی گردونه :

  1. مقدار فعلی state : این مقدار آخرین مقدار state هست که در کامپوننت ذخیره شده.
  2. تابع به روزرسانی state : این تابع به ما اجازه می ده تا مقدار state رو تغییر بدیم و کامپوننت رو دوباره رندر کنیم.

نحوه تعریف state با useState :

import React, { useState } from ‘react’;

 

function ExampleComponent() {

// تعریف state با مقدار اولیه ۰

const [count, setCount] = useState(۰);

 

return (

<div>

<p>شمارنده : {count}</p>

<button onClick={() => setCount(count + ۱)}>

افزایش شمارنده

</button>

</div>

);

}

توی این مثال :

  • useState(۰) رو صدا زدیم تا یه state جدید به اسم count با مقدار اولیه ۰ تعریف کنیم.
  • useState یه آرایه برمی گردونه که ما با استفاده از destructuring مقدار state رو توی count و تابع به روزرسانی state رو توی setCount قرار دادیم.
  • وقتی روی دکمه کلیک می کنیم تابع setCount(count + ۱) رو صدا می زنیم. این کار باعث می شه مقدار count یکی افزایش پیدا کنه و کامپوننت دوباره رندر بشه تا مقدار جدید count رو نمایش بده.

نکات مهم در مورد useState :

  • مقدار اولیه : مقدار اولیه ای که به useState پاس می دید فقط در اولین رندر کامپوننت استفاده می شه. در رندرهای بعدی مقدار state از آخرین به روزرسانی شده اش استفاده می شه.
  • به روزرسانی state : برای به روزرسانی state همیشه باید از تابع به روزرسانی state (setCount در مثال بالا) استفاده کنید. به هیچ وجه مستقیماً مقدار state رو تغییر ندید! React برای تشخیص تغییرات state و رندر مجدد کامپوننت به این توابع به روزرسانی state وابسته است.
  • به روزرسانی state بر اساس مقدار قبلی : گاهی اوقات ممکنه بخواهیم مقدار state رو بر اساس مقدار قبلیش به روزرسانی کنیم. مثلاً توی مثال شمارنده می تونیم به جای setCount(count + ۱) از یه تابع به setCount پاس بدیم :
  • setCount(prevCount => prevCount + ۱);

این روش امن تر و مطمئن تره به خصوص وقتی که به روزرسانی state به صورت ناهمزمان (asynchronous) انجام می شه. React تضمین می کنه که prevCount همیشه مقدار state رو قبل از به روزرسانی نشون می ده.

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

useEffect : مدیریت Side Effects در React

یکی دیگه از هوک های کلیدی و بسیار پرکاربرد useEffect هست. useEffect به ما اجازه می ده تا side effects رو توی کامپوننت های فانکشنال مدیریت کنیم. Side effects چی هستن؟ به طور خلاصه هر عملیاتی که خارج از روال عادی رندر کامپوننت اتفاق بیفته یه side effect محسوب می شه. مثال هایی از side effects عبارتند از :

  • درخواست های HTTP به سرور
  • دستکاری DOM به صورت مستقیم
  • timerها (مثل setTimeout و setInterval)
  • logging

چرا باید side effects رو با useEffect مدیریت کنیم؟

React کامپوننت ها رو بر اساس state و props رندر می کنه. وقتی state یا props تغییر می کنن React کامپوننت رو دوباره رندر می کنه و UI رو به روزرسانی می کنه. اما side effects معمولاً به این چرخه رندر وابسته نیستن و باید به صورت جداگانه مدیریت بشن. useEffect به ما این امکان رو می ده تا side effects رو به صورت declarative و قابل کنترل توی کامپوننت ها تعریف کنیم.

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

useEffect یه هوکه که یه تابع به عنوان اولین آرگومان و یه آرایه وابستگی به عنوان آرگومان دوم می گیره.

import React, { useState, useEffect } from ‘react’;

 

function ExampleComponent() {

const [count, setCount] = useState(۰);

 

// useEffect برای اجرای side effect بعد از هر رندر

useEffect(() => {

// به روزرسانی عنوان سند (document title)

document.title = `شمارنده : ${count}`;

}); // آرایه وابستگی خالی نیست!

 

return (

<div>

<p>شمارنده : {count}</p>

<button onClick={() => setCount(count + ۱)}>

افزایش شمارنده

</button>

</div>

);

}

توی این مثال :

  • useEffect(() => { … }) یه side effect تعریف کردیم که بعد از هر رندر کامپوننت اجرا می شه.
  • تابع داخل useEffect (بهش effect function می گن) کار به روزرسانی عنوان سند رو انجام می ده.
  • آرایه وابستگی : آرگومان دوم useEffect یه آرایه وابستگی هست. این آرایه مشخص می کنه که useEffect چه زمانی باید دوباره اجرا بشه.

آرایه وابستگی :

  • آرایه وابستگی خالی ([]) : اگه آرایه وابستگی رو خالی بذاریم useEffect فقط یک بار بعد از اولین رندر اجرا می شه. این حالت برای side effects که فقط باید یک بار اجرا بشن (مثل درخواست داده از سرور در هنگام mount کامپوننت) مناسبه.
  • آرایه وابستگی با متغیرها ([count]) : اگه متغیرهایی رو توی آرایه وابستگی قرار بدیم useEffect بعد از هر رندر اجرا می شه ولی فقط اگه یکی از متغیرهای داخل آرایه وابستگی تغییر کرده باشه. توی مثال بالا useEffect هر بار که count تغییر می کنه اجرا می شه.
  • بدون آرایه وابستگی : اگه آرایه وابستگی رو کلاً حذف کنیم useEffect بعد از هر رندر اجرا می شه. این حالت معمولاً توصیه نمی شه چون ممکنه باعث اجراهای غیرضروری side effects و مشکلات performance بشه.

Cleanup Function :

useEffect می تونه یه cleanup function هم برگردونه. Cleanup function قبل از اینکه effect function دوباره اجرا بشه (به خاطر تغییر وابستگی ها) یا قبل از اینکه کامپوننت unmount بشه اجرا می شه. Cleanup function برای پاکسازی side effects (مثل لغو درخواست های HTTP پاک کردن timerها و غیره) استفاده می شه.

useEffect(() => {

// side effect

 

return () => {

// cleanup function

};

}, [dependencies]);

 

content_copy download

Use code with caution.JavaScript

مثال cleanup function :

useEffect(() => {

const timer = setInterval(() => {

console.log(‘تیک تاک!’);

}, ۱۰۰۰);

 

return () => {

clearInterval(timer); // پاک کردن timer در cleanup function

};

}, []); // فقط یک بار در mount اجرا بشه و در unmount پاکسازی بشه

useEffect یه هوک قدرتمنده که به ما اجازه می ده side effects رو به صورت کنترل شده و منظم توی کامپوننت های فانکشنال مدیریت کنیم. یادگیری و استفاده صحیح از useEffect برای نوشتن کامپوننت های React کارآمد و بدون مشکل خیلی مهمه.

آموزش استفاده از هوک ها (Hooks) در ReactJS: از مبانی تا پیشرفته

useContext : به اشتراک گذاری State بین کامپوننت ها بدون Props Drilling

فرض کنید یه state دارید که می خواید بین چند تا کامپوننت به اشتراک بذارید. بدون useContext باید props رو از کامپوننت والد به کامپوننت فرزند بعد به نوه و همینطور الی آخر پاس بدید. به این مشکل props drilling می گن و خیلی خسته کننده و غیرقابل نگهداریه.

useContext اومده تا این مشکل رو حل کنه. این هوک به ما اجازه می ده تا به Context دسترسی پیدا کنیم. Context یه راهیه برای به اشتراک گذاشتن مقادیر (مثل state تم زبان و غیره) بین کامپوننت ها بدون اینکه لازم باشه props رو به صورت دستی پاس بدیم.

نحوه استفاده از useContext :

  1. ایجاد Context : اول باید یه Context با استفاده از React.createContext() ایجاد کنیم.
  2. import React from ‘react’;
  3. // ایجاد Context
  4. const ThemeContext = React.createContext(‘light’); // مقدار پیش فرض ‘light’
  5. Provider : بعد باید یه Provider برای Context تعریف کنیم. Provider کامپوننتیه که مقداری رو برای Context فراهم می کنه. هر کامپوننتی که زیر Provider قرار بگیره می تونه به این مقدار دسترسی داشته باشه.
  6. function App() {
  7. return (
  8. <ThemeContext.Provider value=dark> {/* مقدار Context رو ‘dark’ تنظیم می کنیم */}
  9. <Toolbar />
  10. </ThemeContext.Provider>
  11. );
  12. }
  13. Consumer (با useContext) : حالا توی هر کامپوننتی که می خوایم به مقدار Context دسترسی داشته باشیم می تونیم از useContext استفاده کنیم.
  14. import React, { useContext } from ‘react’;
  15. function Toolbar() {
  16. return (
  17. <div>
  18. <ThemedButton />
  19. </div>
  20. );
  21. }
  22. function ThemedButton() {
  23. // دسترسی به مقدار Context با useContext
  24. const theme = useContext(ThemeContext);
  25. return (
  26. <button className={theme}>من یه دکمه با تم هستم!</button>
  27. );
  28. }

توی این مثال :

  • ThemeContext رو با React.createContext(‘light’) ایجاد کردیم. ‘light’ مقدار پیش فرض Context هست که اگه هیچ Providerای مقدار Context رو مشخص نکنه از این مقدار استفاده می شه.
  • ThemeContext.Provider value=dark مقدار Context رو برای تمام کامپوننت های زیر Toolbar به ‘dark’ تنظیم کردیم.
  • توی کامپوننت ThemedButton با استفاده از useContext(ThemeContext) به مقدار Context دسترسی پیدا کردیم و اون رو توی متغیر theme ذخیره کردیم. حالا می تونیم از theme برای استایل دهی دکمه استفاده کنیم.

نکات مهم در مورد useContext :

  • Context.Provider : همیشه باید یه Provider برای Context تعریف کنید تا مقدار Context رو مشخص کنه. اگه Provider تعریف نکنید از مقدار پیش فرض Context استفاده می شه.
  • مقدار Context : مقدار Context می تونه هر چیزی باشه : state آبجکت تابع و غیره.
  • به روزرسانی Context : برای به روزرسانی مقدار Context باید Provider رو دوباره رندر کنید و مقدار جدید رو به value props پاس بدید. هر کامپوننتی که از useContext برای دسترسی به Context استفاده می کنه وقتی مقدار Context تغییر کنه دوباره رندر می شه.

useContext یه هوک خیلی کاربردیه که به ما اجازه می ده state و مقادیر دیگه رو به راحتی بین کامپوننت ها به اشتراک بذاریم و از شر props drilling خلاص بشیم. اگه توی پروژه تون با مشکل props drilling مواجه هستید حتماً useContext رو امتحان کنید.

useReducer : مدیریت State پیچیده با الگوهای Redux-مانند

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

useReducer یه هوکه که برای مدیریت state پیچیده و منطق به روزرسانی state پیچیده طراحی شده. useReducer از الگوی reducer استفاده می کنه که توی کتابخونه های مدیریت state مثل Redux خیلی رایجه. الگوی reducer به ما اجازه می ده تا منطق به روزرسانی state رو به صورت قابل پیش بینی و قابل تست مدیریت کنیم.

نحوه استفاده از useReducer :

useReducer یه هوکه که دو تا آرگومان می گیره :

  1. reducer function : یه تابع که state فعلی و یه action رو به عنوان ورودی می گیره و state جدید رو برمی گردونه.
  2. initial state : مقدار اولیه state.

useReducer یه جفت مقدار برمی گردونه :

  1. state فعلی : مقدار state که توسط reducer مدیریت می شه.
  2. dispatch function : یه تابع که برای ارسال actions به reducer استفاده می شه.

reducer function :

reducer function یه تابع خالصه که دو تا آرگومان می گیره :

  • state : state فعلی.
  • action : یه آبجکت که نوع action و اطلاعات لازم برای به روزرسانی state رو مشخص می کنه.

reducer function باید بر اساس action state جدید رو محاسبه کنه و برگردونه. reducer function نباید side effects داشته باشه! فقط باید state رو به روزرسانی کنه.

مثال useReducer برای شمارنده :

import React, { useReducer } from ‘react’;

 

// reducer function

function counterReducer(state, action) {

switch (action.type) {

case ‘INCREMENT’ :

return { count : state.count + ۱ };

case ‘DECREMENT’ :

return { count : state.count – ۱ };

default :

return state; // در صورت action نامعتبر state رو بدون تغییر برگردون

}

}

 

function ExampleComponent() {

// استفاده از useReducer

const [state, dispatch] = useReducer(counterReducer, { count : ۰ }); // state اولیه : { count : ۰ }

 

return (

<div>

<p>شمارنده : {state.count}</p>

<button onClick={() => dispatch({ type : ‘INCREMENT’ })}> {/* ارسال action ‘INCREMENT’ */}

افزایش شمارنده

</button>

<button onClick={() => dispatch({ type : ‘DECREMENT’ })}> {/* ارسال action ‘DECREMENT’ */}

کاهش شمارنده

</button>

</div>

);

}

توی این مثال :

  • counterReducer یه reducer function هست که بر اساس action.type state شمارنده رو به روزرسانی می کنه.
  • useReducer(counterReducer, { count : ۰ }) رو صدا زدیم تا useReducer رو با reducer function و state اولیه { count : ۰ } مقداردهی اولیه کنیم.
  • useReducer یه آرایه برمی گردونه که state فعلی رو توی state و dispatch function رو توی dispatch قرار دادیم.
  • برای افزایش یا کاهش شمارنده از dispatch برای ارسال actions به reducer استفاده می کنیم. مثلاً dispatch({ type : ‘INCREMENT’ }) یه action با نوع ‘INCREMENT’ به reducer ارسال می کنه.

مزایای useReducer :

  • مدیریت state پیچیده : useReducer برای مدیریت stateهای پیچیده که شامل چندین زیرمجموعه و منطق به روزرسانی پیچیده هستن خیلی مناسبه.
  • منطق به روزرسانی state قابل پیش بینی : به خاطر استفاده از reducer function منطق به روزرسانی state کاملاً قابل پیش بینی و قابل تست می شه.
  • مشابه Redux : اگه با Redux آشنا هستید الگوی reducer برای شما آشنا خواهد بود و یادگیری useReducer براتون خیلی راحت تر می شه.

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

  • وقتی state پیچیده است و شامل چندین زیرمجموعه است.
  • وقتی منطق به روزرسانی state پیچیده است و شامل چند مرحله است.
  • وقتی می خواهید منطق به روزرسانی state رو به صورت قابل پیش بینی و قابل تست مدیریت کنید.

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

useRef : دسترسی به عناصر DOM و نگهداری مقادیر بین رندرها

useRef یه هوکه که دو تا کاربرد اصلی داره :

  1. دسترسی به عناصر DOM به صورت مستقیم : با useRef می تونیم یه reference به یه عنصر DOM ایجاد کنیم و به صورت مستقیم به اون عنصر دسترسی داشته باشیم. این کار معمولاً برای مواردی مثل فوکوس کردن روی یه input اجرای متدهای DOM API و غیره استفاده می شه.
  2. نگهداری مقادیر بین رندرها بدون رندر مجدد کامپوننت : با useRef می تونیم مقادیری رو ذخیره کنیم که بین رندرهای کامپوننت حفظ بشن بدون اینکه تغییر این مقادیر باعث رندر مجدد کامپوننت بشه. این کار برای مواردی مثل نگهداری timer ID شمارنده رندرها و غیره استفاده می شه.

نحوه استفاده از useRef :

useRef یه هوکه که یه مقدار اولیه به عنوان آرگومان می گیره و یه آبجکت ref برمی گردونه. آبجکت ref یه property به اسم current داره که مقدار ref رو نگه می داره.

دسترسی به عناصر DOM :

import React, { useRef, useEffect } from ‘react’;

 

function ExampleComponent() {

// ایجاد ref

const inputRef = useRef(null);

 

useEffect(() => {

// بعد از mount کامپوننت روی input فوکوس کن

inputRef.current.focus();

}, []); // فقط یک بار در mount اجرا بشه

 

return (

<div>

<input ref={inputRef} type=text /> {/* اتصال ref به عنصر input */}

</div>

);

}

توی این مثال :

  • useRef(null) رو صدا زدیم تا یه ref به اسم inputRef با مقدار اولیه null ایجاد کنیم.
  • به عنصر input attribute ref={inputRef} رو اضافه کردیم. این کار باعث می شه React عنصر DOM مربوط به input رو به property current آبجکت inputRef اختصاص بده.
  • توی useEffect بعد از mount کامپوننت با استفاده از inputRef.current.focus() روی input فوکوس می کنیم.

نگهداری مقادیر بین رندرها :

import React, { useRef, useState, useEffect } from ‘react’;

 

function ExampleComponent() {

const [count, setCount] = useState(۰);

const renderCount = useRef(۰); // ref برای شمارنده رندرها

 

useEffect(() => {

renderCount.current = renderCount.current + ۱; // افزایش شمارنده رندرها در هر رندر

});

 

return (

<div>

<p>شمارنده : {count}</p>

<p>تعداد رندرها : {renderCount.current}</p>

<button onClick={() => setCount(count + ۱)}>

افزایش شمارنده

</button>

</div>

);

}

توی این مثال :

  • useRef(۰) رو صدا زدیم تا یه ref به اسم renderCount با مقدار اولیه ۰ ایجاد کنیم.
  • توی useEffect در هر رندر کامپوننت مقدار renderCount.current رو یکی افزایش می دیم.
  • مقدار renderCount.current بین رندرها حفظ می شه ولی تغییرش باعث رندر مجدد کامپوننت نمی شه. به همین خاطر شمارنده رندرها به درستی کار می کنه.

نکات مهم در مورد useRef :

  • current property : مقدار ref همیشه توی property current آبجکت ref ذخیره می شه.
  • تغییر ref.current باعث رندر مجدد نمی شه : تغییر مقدار ref.current باعث رندر مجدد کامپوننت نمی شه. useRef برای نگهداری مقادیری که نباید باعث رندر مجدد کامپوننت بشن مناسبه.
  • مقدار اولیه : مقدار اولیه ای که به useRef پاس می دید فقط در اولین رندر کامپوننت استفاده می شه. در رندرهای بعدی مقدار ref از آخرین به روزرسانی شده اش استفاده می شه.

useRef یه هوک خیلی منعطفه که کاربردهای متنوعی داره. با useRef می تونیم به عناصر DOM دسترسی داشته باشیم و مقادیری رو بین رندرها بدون رندر مجدد کامپوننت نگهداری کنیم.

هوک های سفارشی (Custom Hooks) : استفاده مجدد از منطق هوک ها

یکی از قوی ترین ویژگی های هوک ها امکان ایجاد هوک های سفارشی هست. هوک های سفارشی به ما اجازه می دن تا منطق هوک ها رو کپسوله کنیم و بین کامپوننت های مختلف به اشتراک بذاریم. هوک های سفارشی فقط توابع جاوااسکریپتی هستن که از هوک های built-in React (مثل useState, useEffect, useContext, و غیره) استفاده می کنن.

چرا باید هوک های سفارشی ایجاد کنیم؟

  • استفاده مجدد از منطق : هوک های سفارشی به ما اجازه می دن تا منطق stateful و side effect رو به صورت قابل استفاده مجدد بین کامپوننت ها به اشتراک بذاریم. به جای اینکه کد مشابه رو توی کامپوننت های مختلف تکرار کنیم می تونیم یه هوک سفارشی ایجاد کنیم و اون رو توی کامپوننت های مختلف استفاده کنیم.
  • سازماندهی کد : هوک های سفارشی به ما کمک می کنن تا کد کامپوننت ها رو سازمان دهی کنیم و منطق پیچیده رو به توابع کوچکتر و قابل مدیریت تر تقسیم کنیم.
  • تست پذیری : هوک های سفارشی رو می شه به صورت جداگانه تست کرد که تست کردن کامپوننت هایی که ازشون استفاده می کنن رو راحت تر می کنه.

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

  1. ایجاد یه تابع جاوااسکریپتی : هوک سفارشی فقط یه تابع جاوااسکریپتیه. اسم هوک سفارشی باید با use شروع بشه (مثلاً useCounter, useFetch, useTheme, و غیره). این قرارداد به React می گه که این تابع یه هوکه و باید از قوانین هوک ها پیروی کنه.
  2. استفاده از هوک های built-in : هوک سفارشی باید از حداقل یک هوک built-in React (مثل useState, useEffect, useContext, و غیره) استفاده کنه.
  3. برگردوندن مقدار : هوک سفارشی معمولاً یه مقدار برمی گردونه که کامپوننت ها می تونن ازش استفاده کنن. این مقدار می تونه state توابع یا هر چیز دیگه ای باشه.

مثال هوک سفارشی useCounter :

import { useState } from ‘react’;

 

// هوک سفارشی useCounter

function useCounter(initialCount = ۰) {

const [count, setCount] = useState(initialCount);

 

const increment = () => setCount(prevCount => prevCount + ۱);

const decrement = () => setCount(prevCount => prevCount – ۱);

const reset = () => setCount(initialCount);

 

return {

count,

increment,

decrement,

reset,

};

}

 

function ExampleComponent() {

// استفاده از هوک سفارشی useCounter

const { count, increment, decrement, reset } = useCounter(۱۰); // شمارنده با مقدار اولیه ۱۰

 

return (

<div>

<p>شمارنده : {count}</p>

<button onClick={increment}>افزایش</button>

<button onClick={decrement}>کاهش</button>

<button onClick={reset}>ریست</button>

</div>

);

}

توی این مثال :

  • useCounter یه هوک سفارشیه که منطق مدیریت شمارنده رو کپسوله کرده.
  • useCounter از useState برای مدیریت state شمارنده استفاده می کنه.
  • useCounter توابع increment, decrement, و reset رو برای به روزرسانی شمارنده فراهم می کنه.
  • useCounter یه آبجکت برمی گردونه که شامل count و توابع به روزرسانی شمارنده است.
  • توی ExampleComponent از useCounter() برای استفاده از منطق شمارنده استفاده می کنیم.

نکات مهم در مورد هوک های سفارشی :

  • نامگذاری : اسم هوک سفارشی باید با use شروع بشه.
  • استفاده از هوک های built-in : هوک سفارشی باید از حداقل یک هوک built-in React استفاده کنه.
  • قابل استفاده مجدد : هوک های سفارشی باید قابل استفاده مجدد در کامپوننت های مختلف باشن.
  • قابل تست : هوک های سفارشی باید قابل تست باشن.

هوک های سفارشی یه ابزار قدرتمند برای استفاده مجدد از منطق هوک ها و سازماندهی کد کامپوننت ها هستن. اگه توی پروژه تون منطق مشابهی رو توی چند تا کامپوننت استفاده می کنید حتماً به ایجاد هوک های سفارشی فکر کنید.

قوانین هوک ها : پیروی از اصول برای جلوگیری از مشکلات

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

قوانین هوک ها :

  1. فقط در بدنه کامپوننت های فانکشنال یا هوک های سفارشی صدا زده بشید : هوک ها رو نباید توی توابع جاوااسکریپتی معمولی کلاس ها یا جاهای دیگه صدا بزنیم. فقط باید توی بدنه کامپوننت های فانکشنال یا هوک های سفارشی صدا زده بشن.
  2. فقط در سطح بالای کامپوننت صدا زده بشید : هوک ها رو نباید توی حلقه ها شرط ها یا توابع تودرتو صدا بزنیم. هوک ها باید همیشه در سطح بالای کامپوننت صدا زده بشن قبل از هرگونه شرط یا حلقه.

چرا این قوانین مهم هستن؟

React برای اینکه بتونه هوک ها رو به درستی مدیریت کنه و state و side effects رو به کامپوننت ها مرتبط کنه به این قوانین نیاز داره. React به ترتیب صدا زدن هوک ها در هر رندر وابسته است. اگه ترتیب صدا زدن هوک ها در رندرهای مختلف تغییر کنه React نمی تونه state و side effects رو به درستی مدیریت کنه و ممکنه با مشکلات مواجه بشیم.

مثال نقض قانون اول :

function ExampleComponent() {

function handleClick() {

useState(۰); // ❌ نقض قانون اول : هوک در تابع جاوااسکریپتی معمولی صدا زده شده

}

 

return (

<button onClick={handleClick}>کلیک کن</button>

);

}

مثال نقض قانون دوم :

function ExampleComponent({ showCount }) {

if (showCount) {

useState(۰); // ❌ نقض قانون دوم : هوک در شرط صدا زده شده

}

 

return (

<div>

{/* … */}

</div>

);

}

React Lint Plugin :

React یه پلاگین lint به اسم eslint-plugin-react-hooks ارائه داده که به صورت خودکار قوانین هوک ها رو چک می کنه و اگه قانونی نقض بشه هشدار می ده. استفاده از این پلاگین برای جلوگیری از مشکلات مربوط به قوانین هوک ها خیلی توصیه می شه.

نکات مهم در مورد قوانین هوک ها :

  • همیشه قوانین رو رعایت کنید.
  • از eslint-plugin-react-hooks استفاده کنید.
  • اگه مطمئن نیستید که دارید قوانین رو درست رعایت می کنید به مستندات React مراجعه کنید.

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

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

بعد از آشنایی با هوک های پایه می تونیم به الگوهای پیشرفته تر و بهترین روش های استفاده از هوک ها بپردازیم. این الگوها و روش ها به ما کمک می کنن تا کدهای تمیزتر کارآمدتر و قابل نگهداری تری با هوک ها بنویسیم.

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

  1. هوک های سفارشی پیچیده : می تونیم هوک های سفارشی پیچیده تری ایجاد کنیم که از چندین هوک built-in استفاده می کنن و منطق پیچیده تری رو کپسوله می کنن. مثلاً می تونیم یه هوک سفارشی برای مدیریت فرم مدیریت pagination مدیریت احراز هویت و غیره ایجاد کنیم.
  2. ترکیب هوک ها : می تونیم هوک ها رو با هم ترکیب کنیم تا منطق پیچیده تری رو ایجاد کنیم. مثلاً می تونیم از useState و useEffect با هم برای مدیریت state و side effects مرتبط با هم استفاده کنیم.
  3. هوک های HOC-مانند : می تونیم هوک های سفارشی ایجاد کنیم که رفتاری شبیه به HOCها داشته باشن. مثلاً می تونیم یه هوک سفارشی ایجاد کنیم که یه کامپوننت رو با یه سری props خاص enhanced کنه.

بهترین روش های استفاده از هوک ها :

  1. کد رو modular و reusable نگه دارید : سعی کنید منطق stateful و side effect رو تا حد امکان به هوک های سفارشی منتقل کنید تا کد کامپوننت ها تمیزتر و قابل استفاده مجددتر بشه.
  2. از قوانین هوک ها پیروی کنید.
  3. به performance توجه کنید : اجراهای غیرضروری side effects رو با استفاده از آرایه وابستگی useEffect کنترل کنید. از useCallback و useMemo برای بهینه سازی performance استفاده کنید.
  4. کد رو تست کنید : هوک های سفارشی رو به صورت جداگانه تست کنید و کامپوننت هایی که ازشون استفاده می کنن رو هم تست کنید.
  5. مستندات React رو مطالعه کنید : مستندات React منبع خیلی خوبی برای یادگیری الگوهای پیشرفته و بهترین روش های استفاده از هوک هاست.

ابزارهای کمکی :

  • React DevTools : React DevTools یه ابزار مرورگره که به ما کمک می کنه تا کامپوننت های React رو inspect کنیم و state و props و هوک ها رو ببینیم. React DevTools برای دیباگ کردن مشکلات مربوط به هوک ها خیلی مفیده.
  • eslint-plugin-react-hooks : قبلاً هم گفتیم این پلاگین lint به صورت خودکار قوانین هوک ها رو چک می کنه و از مشکلات احتمالی جلوگیری می کنه.

یادگیری الگوهای پیشرفته و بهترین روش های استفاده از هوک ها یه فرایند مداوم و تمرین محوره. با تمرین و تجربه کم کم با این الگوها و روش ها آشنا می شید و می تونید کدهای React بهتری بنویسید.

اشتباهات رایج و رفع اشکال هوک ها

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

اشتباهات رایج در استفاده از هوک ها :

  1. نقض قوانین هوک ها : همونطور که قبلاً گفتیم نقض قوانین هوک ها (صدا زدن هوک ها در جاهای نامناسب یا به ترتیب نامناسب) یکی از رایج ترین اشتباهات هست. این اشتباه معمولاً باعث مشکلات غیرمنتظره و باگ های عجیب و غریب می شه.
  2. وابستگی های اشتباه در useEffect : اشتباه در تنظیم آرایه وابستگی useEffect می تونه باعث اجراهای غیرضروری side effects یا اجرا نشدن side effects در زمان مناسب بشه. مثلاً اگه یه وابستگی رو از آرایه وابستگی جا بندازیم ممکنه side effect با مقدار قدیمی وابستگی اجرا بشه. یا اگه وابستگی های زیادی رو توی آرایه وابستگی قرار بدیم ممکنه side effect بیش از حد اجرا بشه.
  3. به روزرسانی state در رندر : به روزرسانی state در بدنه کامپوننت (خارج از توابع event handler یا useEffect) باعث یه رندر بی نهایت می شه. چون به روزرسانی state باعث رندر مجدد کامپوننت می شه و اگه توی رندر state رو دوباره به روزرسانی کنیم یه چرخه رندر بی نهایت ایجاد می شه.
  4. فراموش کردن cleanup function در useEffect : اگه side effectی داشته باشیم که نیاز به cleanup داشته باشه (مثل timer یا subscription) فراموش کردن cleanup function می تونه باعث memory leak یا مشکلات دیگه بشه.
  5. استفاده بیش از حد از useContext : با اینکه useContext برای به اشتراک گذاری state بین کامپوننت ها خیلی خوبه ولی استفاده بیش از حد ازش ممکنه باعث پیچیدگی و سخت شدن نگهداری کد بشه. بهتره فقط در مواردی که واقعاً نیاز داریم از useContext استفاده کنیم و از props drilling جلوگیری کنیم.

نحوه رفع اشکال هوک ها :

  1. بررسی قوانین هوک ها : اولین قدم برای رفع اشکال هوک ها بررسی قوانین هوک هاست. مطمئن بشید که دارید قوانین رو درست رعایت می کنید. از eslint-plugin-react-hooks برای چک کردن خودکار قوانین استفاده کنید.
  2. بررسی آرایه وابستگی useEffect : اگه مشکل مربوط به useEffect هست آرایه وابستگی رو با دقت بررسی کنید. مطمئن بشید که تمام وابستگی های لازم رو توی آرایه قرار دادید و هیچ وابستگی غیرضروری توی آرایه نیست.
  3. استفاده از React DevTools : React DevTools ابزار خیلی خوبی برای دیباگ کردن مشکلات مربوط به هوک هاست. با React DevTools می تونید state props و هوک های کامپوننت رو inspect کنید و ببینید چه مقادیری دارن و چه اتفاقی داره می افته.
  4. console.log : اگه با React DevTools نتونستید مشکل رو پیدا کنید از console.log برای debug کردن استفاده کنید. مقادیر state props و وابستگی های useEffect رو توی کنسول log کنید تا ببینید چه مقادیری دارن و آیا مقادیر درست هستن یا نه.
  5. جستجو در اینترنت و پرسیدن سوال : اگه بازم نتونستید مشکل رو حل کنید تو اینترنت جستجو کنید و ببینید آیا کسی دیگه با مشکل مشابهی مواجه شده یا نه. اگه جواب رو پیدا نکردید توی انجمن های برنامه نویسی یا Stack Overflow سوال بپرسید.

رفع اشکال هوک ها ممکنه گاهی اوقات چالش برانگیز باشه ولی با تمرین و تجربه کم کم مهارتتون توی دیباگ کردن هوک ها بهتر می شه. مهم اینه که صبور باشید و از ابزارهای دیباگینگ React به درستی استفاده کنید.

نتیجه گیری : هوک ها انقلابی در React!

هوک ها واقعاً یه انقلاب توی دنیای React بودن. اون ها روش کدنویسی React رو برای همیشه تغییر دادن و زندگی رو برای ما دولوپرها خیلی آسون تر کردن. با هوک ها دیگه لازم نیست با پیچیدگی های کامپوننت های کلاسی دست و پنجه نرم کنیم و می تونیم کدهای خیلی تمیزتر خواناتر و قابل استفاده مجددتری بنویسیم.

توی این مقاله با هوک های اصلی React (useState, useEffect, useContext, useReducer, useRef) آشنا شدیم نحوه استفاده ازشون رو یاد گرفتیم قوانین هوک ها رو بررسی کردیم الگوهای پیشرفته و بهترین روش ها رو مرور کردیم و اشتباهات رایج و نحوه رفع اشکال هوک ها رو هم بررسی کردیم.

یادگیری هوک ها یه سرمایه گذاری ارزشمنده برای هر دولوپر React. با تسلط به هوک ها می تونید به یه دولوپر React حرفه ای تر تبدیل بشید و پروژه های React رو با سرعت و کیفیت بالاتری توسعه بدید. پس اگه هنوز با هوک ها آشنا نیستید پیشنهاد می کنم همین الان شروع به یادگیریشون کنید. مطمئنم پشیمون نمی شید!

توصیه های نهایی برای یادگیری هوک ها :

  • مستندات React رو به دقت مطالعه کنید. مستندات React بهترین منبع برای یادگیری هوک هاست.
  • تمرین کنید تمرین کنید تمرین کنید! بهترین راه برای یادگیری هوک ها تمرین کردنه. پروژه های کوچیک React با هوک ها بسازید و با هوک های مختلف بازی کنید.
  • کد دیگران رو بخونید. کدهای پروژه های open-source React که از هوک ها استفاده می کنن رو بخونید و ببینید چطور از هوک ها استفاده کردن.
  • در جامعه React فعال باشید. سوال بپرسید جواب بدید و با دولوپرهای دیگه React در ارتباط باشید.

با تلاش و پشتکار مطمئنم شما هم می تونید به یه استاد هوک ها تبدیل بشید! موفق باشید!

پرسش و پاسخ متداول کاربران

۱. آیا هوک ها جایگزین کامپوننت های کلاسی شده اند؟

نه هوک ها جایگزین کامپوننت های کلاسی نشده اند. کامپوننت های کلاسی هنوز هم توی React وجود دارن و کار می کنن. هوک ها فقط یه روش جدید و مدرن برای نوشتن کامپوننت های React هستن. شما می تونید توی پروژه هاتون هم از کامپوننت های فانکشنال با هوک ها و هم از کامپوننت های کلاسی استفاده کنید. ولی به طور کلی کامپوننت های فانکشنال با هوک ها به دلایلی که توی مقاله گفتیم معمولاً ترجیح داده می شن.

۲. آیا یادگیری هوک ها سخته؟

یادگیری هوک ها ممکنه اولش یکم گیج کننده به نظر برسه به خصوص اگه با مفاهیم state و lifecycle توی کامپوننت های کلاسی آشنا باشید. ولی با تمرین و مطالعه مستندات React یادگیری هوک ها خیلی سخت نیست. مهم اینه که قوانین هوک ها رو درک کنید و به درستی ازشون استفاده کنید. هوک ها در واقع کدنویسی React رو خیلی ساده تر و لذت بخش تر می کنن.

۳. آیا استفاده از هوک ها باعث بهبود performance می شه؟

به طور مستقیم هوک ها لزوماً باعث بهبود performance نمی شن. ولی هوک ها به ما کمک می کنن تا کدهای تمیزتر و سازمان یافته تری بنویسیم که این موضوع به طور غیرمستقیم می تونه به بهبود performance کمک کنه. همچنین هوک ها امکان بهینه سازی performance رو با استفاده از هوک هایی مثل useCallback و useMemo فراهم می کنن. در کل استفاده درست از هوک ها می تونه به performance بهتر پروژه های React کمک کنه.

آیا شما به دنبال کسب اطلاعات بیشتر در مورد "آموزش استفاده از هوک ها (Hooks) در ReactJS: از مبانی تا پیشرفته" هستید؟ با کلیک بر روی تکنولوژی, کسب و کار ایرانی، ممکن است در این موضوع، مطالب مرتبط دیگری هم وجود داشته باشد. برای کشف آن ها، به دنبال دسته بندی های مرتبط بگردید. همچنین، ممکن است در این دسته بندی، سریال ها، فیلم ها، کتاب ها و مقالات مفیدی نیز برای شما قرار داشته باشند. بنابراین، همین حالا برای کشف دنیای جذاب و گسترده ی محتواهای مرتبط با "آموزش استفاده از هوک ها (Hooks) در ReactJS: از مبانی تا پیشرفته"، کلیک کنید.