React Hooks ایسے فنکشنز ہیں جو آپکو کلاس لکھے بغیر فنکشنل کمپونینٹس میں اسٹیٹ، افیکٹس، کانٹیکسٹ اور React کی دیگر خصوصیات استعمال کرنے کی اجازت دیتے ہیں۔ React 16.8 مین متعارف کرایے گئے، ہوک نے HOC اور render props جیسے پیچیدہ پٹرنز کی جگہ لے کر ڈیویلپمنٹ کے نظریے کو بنیادی طور پر بدل دیا۔ React, 2024 کے مطابق، 15 مضمن ہوک ہیں جو تمام کمپونینٹ مینجمنٹ کے مناظر کو کرانّے ہیں۔
اہم نکات
React Hooks React میں ضمنی فنکشنز کا ایک سیٹ ہے جو آپکو کلاس بنائے بغیر فریم ورک کے اندرونی میکانزم سے «منسلک ہونے» کی اجازت دیتا ہے۔ React 16.8 سے پہلے، فنکشنل کمپونینٹ صرف props وصول کر سکتے تھے اور JSX واپس کر سکتے تھے — کسی بھی پیچیدہ لاجک کے لیے ایک کلاس کمپونینٹ درکار تھا۔
کلاس کمپونینٹس کا مسئلہ متعلقہ لاجک کی تقسیم ہے۔ ایک ہی اڦی سے متعلق کوڈ (مثالیتن، ایک WebSocket سبسکرائیپشن) جبراً componentDidMount، componentDidUpdate اور componentWillUnmount کے درمیان تقسیم کیا جاتا تھا۔ ہوک اسے حل کرتے ہیں: تمام لاجک ایک useEffect میں گروپ ہوتا ہے۔
دوسرا مسئلہ لاجک کا دوبارہ استعمال ہے۔ کلاس کمپونینٹس کے درمیان اسٹیٹ لاجک کو دوبارہ استعمال کرنے کے لیے، آپکو HOC (اعلی درجہ کے کمپونینٹس) یا render props لاگو کرنے پڑتے تھے — دونوں پٹرنز نے کمپونینٹ ٹری میں اضافی نیڈنگ بنایا۔ کسٹم ہوک بغیر نیڈنگ کے اسے حل کرتے ہیں۔
useState سب سے بنیادی ہوک ہے۔ یہ ایک ابتدائی قیمت لیتا ہے اور ایک ٹیوپل واپس کرتا ہے: موجودہ قیمت اور اسے اپڈیٹ کرنے کا ایک فنکشن۔ کلاسوں میں this.setState کے برعکس، useState آبجیکٹس کو مرج نہیں کرتا — نئی اسٹیٹ ایک مخصوص useState کال کے لیے پچھلی اسٹیٹ کو مکمل طور پر بدل دیتی ہے۔
import React, { useState } from 'react';
function Form() {
const [text, setText] = useState('');
const [submitting, setSubmitting] = useState(false);
async function handleSubmit() {
setSubmitting(true);
await fetch('/api/submit', {
method: 'POST',
body: JSON.stringify({ text })
});
setSubmitting(false);
}
return (
<div>
<input
value={text}
onChange={e => setText(e.target.value)}
/>
<button onClick={handleSubmit}
disabled={submitting}>
{submitting ? 'Saving...' : 'Submit'}
</button>
</div>
);
}
useState کا سیٹر ایک فنکشن قبول کر سکتا ہے جو پچھلی قیمت وصول کرتا ہے اور ایک نئی قیمت واپس کرتا ہے۔ فنکشنل شکل اس وقت لازمی ہے جب نئی اسٹیٹ پچھلی سے حساب کی جاتی ہے اور بیچ کی گئی setState کالز ممکن ہیں — ہر کال موجودہ پچھلی قیمت وصول کرے گا۔
useEffect فنکشنل کمپونینٹس میں سائیڈ افیکٹس کرنے کا ایک ہوک ہے۔ یہ دو ارگومنٹ لیتا ہے: ایک افیکٹ فنکشن اور ایک انحصاریت ارے۔ React ہر رینڈر کے بعد افیکٹ چلاتا ہے، لیکن جب انحصاریتیں متعین کی جاتی ہیں — صرف اس وقت جب ان میں سے کوئی بدلتی ہے۔
ایک خالی انحصاریت ارے [] کا مطلب ہے کے افیکٹ پہلے رینڈر کے بعد ایک بار چلتا ہے (componentDidMount کے مشاب۔) افیکٹ سے ایک فنکشن واپس کرنا ایک صفائی ہے جو ان ماؤنٹ پر (componentWillUnmount کے مشاب۔) اور افیکٹ کو دوبارہ چلانے سے پہلے چلتی ہے۔
import React, { useState, useEffect } from 'react';
function ChatRoom({ roomId }) {
const [messages, setMessages] = useState([]);
useEffect(() => {
const socket = new WebSocket(`wss://chat/${roomId}`);
socket.onmessage = (event) => {
setMessages(prev => [...prev, JSON.parse(event.data)]);
};
// صفائی - ساکٹ بند کریں
return () => socket.close();
}, [roomId]);
return <ul>
{messages.map((msg, i) =>
<li key={i}>{msg.text}</li>
)}
</ul>;
}
useEffect کی انحصاریتیں افیکٹ اور باہری دنیا کے درمیان ایک واحد تعلق ہیں۔ اگر افیکٹ props یا اسٹیٹ سے ایک متغیر استعمال کرتا ہے، تو اسے انحصاریت ارے میں ہونا چاہیے۔ اس قاعدے کو نظر انداز کرنا پرانی closures کے ساتھ بگز کا ذریعہ ہے۔
useContext کانٹیکسٹ کی قیمتیں پڑھنے کا ایک ہوک ہے۔ یہ React.createContext سے بنایا گیا ایک کانٹیکسٹ آبجیکٹ لیتا ہے اور موجودہ قیمت واپس کرتا ہے۔ اگر کانٹیکسٹ بدلتا ہے، تو کمپونینٹ خودکار نئی قیمت کے ساتھ دوبارہ رینڈر ہوتا ہے۔
useContext سے پہلے، فنکشنل کمپونینٹس میں کانٹیکسٹ تک رسائی کے لیے Context.Consumer میں لپیٹنے کی ضرورت تھی، جس سے نیڈنگ بنتی تھی۔ useContext Consumer کو مکمل طور پر ختم کر دیتا ہے — بس فنکشنل کمپونینٹ میں کہیں بھی ہوک کو کال کریں۔
import React, { createContext, useContext } from 'react';
const ThemeContext = createContext('ہلکا');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button
className={`btn btn-${theme}`}
>
{theme === 'dark' ? 'moon' : '☀️'}
</button>;
}
useContext Redux یا عالمی اسٹیٹ کا متبادل نہیں ہے۔ React کم بدلنے والی قیمتیں — ثیم، مقامی ترتیبات، اتھیائی کے لیے کانٹیکسٹ استعمال کرنے کی سفارش کرتا ہے۔ اڨ کی جانے والے ڈیٹا کے لیے، ہر دوبارہ رینڈر سب کانٹیکسٹ صرف کرنے والوں کا دوبارہ حساب لگائے گا، جو کارکردگی کو کم کر سکتا ہے۔
useReducer پیچیدہ اپڈیٹ لاجک والی اسٹیٹ کے لیے useState کا ایک متبادل ہے۔ یہ ایک ریڈیوسر فنکشن اور ابتدائی اسٹیٹ لیتا ہے، موجودہ اسٹیٹ اور ایک dispatch فنکشن واپس کرتا ہے۔ ریڈیوسر موجودہ اسٹیٹ اور ایک عمل وصول کرتا ہے، ایک نئی اسٹیٹ واپس کرتا ہے — بغیر سائیڈ افیکٹ کے ایک خالص فنکشن۔
useReducer خاص طور پر مفید ہے جب ایکاثر عمل (set, reset, increment, addItem) ایک اسٹیٹ کا انتظام کرتے ہیں۔ مختلف setterز کے ساتھ ایکاثر useState کالز کے بجائے — واضح عمل اقسام کے ساتھ ایک ریڈیوسر۔ یہ لاجک کو پیش قیاس پذیر اور آسانی سے ٹیسٹ کرنے قابل بناتا ہے۔
import React, { useReducer } from 'react';
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { ...state, count: state.count + 1 };
case 'setStep':
return { ...state, step: action.step };
case 'reset':
return { count: 0, step: 1 };
default:
throw new Error('Unknown action: ' + action.type);
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, {
count: 0,
step: 1
});
return (
<>
<p>Count: {state.count}</p>
<button
onClick={() => dispatch({ type: 'increment' })}>+</button>
<button
onClick={() => dispatch({ type: 'reset' })}>Reset</button>
</>
);
}
useRef ایک قابل تبدیل آبجیکٹ بناتا ہے جو رینڈرز کے درمیان برقرار رہتا ہے۔ current کو بدلنا دوبارہ رینڈر کو متحرک نہیں کرتا۔ اہم استعمالات DOM عناصر تک رسائی اور قابل تبدیل قیمتیں (ٹائمرز، پچھلی قیمتیں، لائبریری انسٹینسز) ذخیرے کرنا ہے۔
useMemo ایک فنکشن کے نتیجے کو میمائیز کرتا ہے۔ یہ قیمت کو صرف اس وقت دوبارہ حساب کرتا ہے جب ایک انحصاریت بدلتی ہے۔ مہنگے حسابوں کے لیے استعمال کریں — بڑے ارے کو فلٹر کرنا، ترتیب دینا، ڈیٹا فارمیٹنگ۔ useCallback فنکشنز کو میمائیز کرنے کے لیے useMemo کا ایک خاص معاملہ ہے۔
import React, { useRef, useMemo, useCallback } from 'react';
function SearchPage({ items, query, onItemSelect }) {
const inputRef = useRef(null);
// ماؤنٹ پر خودکار فوکس
useEffect(() => {
inputRef.current?.focus();
}, []);
// فلٹر شدہ نتیجے کو میمائیز کریں
const filtered = useMemo(() => {
return items.filter(item =>
item.name.toLowerCase()
.includes(query.toLowerCase())
);
}, [items, query]);
// کالبیک کو میمائیز کریں
const handleSelect = useCallback((id) => {
onItemSelect(id);
}, [onItemSelect]);
return (
<div>
<input ref={inputRef}
value={query}
onChange={e => setQuery(e.target.value)}
/>
<ul>
{filtered.map(item =>
<li key={item.id}>
<button
onClick={() => handleSelect(item.id)}>
{item.name}
</button>
</li>
)}
</ul>
</div>
);
}
ایک اہم قاعدہ: useRef، useMemo اور useCallback اپٹیمائیزیشن اوزار ہیں، لازمی تعمیرات نہیں۔ سب کُچھ useMemo میں لپیٹیں — پہلے کارکردگی ناپیں۔ جلد اپٹیمائیزیشن کوڈ کو پیچیدہ کرتا ہے۔ React کمپونینٹس کو تیزی سے رینڈر کرتا ہے; useMemo صرف اس وقت ضروری ہے جب حساب واقعی مہنگے ہوں (O(n²) اور اوپر)۔
React نے ہوک کے لیے دو سخت قواعد متعارف کرائے۔ پہلا: ہوک کو صرف اوپری سطح پر کال کریں — شرائط، لوپز یا نیڈے کیئے گئے فنکشنز کے اندر نہیں۔ دوسرا: ہوک کو صرف React فنکشنل کمپونینٹس یا کسٹم ہوک سے کال کریں۔ ESLint پلاگائن eslint-plugin-react-hooks خودکار دونوں قواعد کی جانچ کرتا ہے۔
سب سے عام غلطی ہوک کالز کے ترتیب کی خلاف ورزی ہے۔ React رینڈرز کے درمیان ہوک کالز کے ترتیب پر انحصار کرتا ہے۔ اگر ایک ہوک ایک شرط کے اندر ہے اور ایک رینڈر میں نہیں چلتا، تو بعد کے سب ہوک شفٹ ہو جاتے ہیں، جس سے بگز ہوتے ہیں۔
| غلطی | کیا ہوتا ہے | حل |
|---|---|---|
| شرط میں ہوک | ہوک کا ترتیب ٹوٹ جاتا ہے | شرط کی لاجک کو ہوک کے اندر لے جائیں |
| Stale closure | افیکٹ پرانی قیمت استعمال کرتا ہے | تمام انحصاریتیں ارے میں شامل کریں |
| لاتعداد لوپ | انحصاریتوں کے بغیر useEffect اسٹیٹ بدلتا ہے | انحصاریتیں متعین کریں یا useReducer استعمال کریں |
| render میں ref بدلنا | فنکشن باڈی میں سائیڈ افیکٹ | میوٹیشنز کو useEffect میں لے جائیں |
دوسری عام غلطی useEffect میں stale closure ہے۔ اگر افیکٹ انحصاریتوں میں متعین نہیں کردہ ایک متغیر استعمال کرتا ہے، تو افیکٹ اپنی تخلیق کے وقت اس کی قیمت کو «پکڑتا» ہے۔ حل یہ ہے کے مستعمل تمام متغیرات کو ہمیشہ انحصاریت ارے میں شامل کریں۔ اگر بہت زیادہ انحصاریتیں ہیں، تو افیکٹ کو کئی حصوں میں تقسیم کرنے پر غور کریں۔
اڨ پوچھے جانے والے سوالات
React رینڈرز کے درمیان ہوک کالز کے ترتیب پر انحصار کرتا ہے۔ اگر ایک ہوک ایک شرط کے اندر بلایا جاتا ہے اور ایک رینڈر میں نہیں چلتا، تو بعد کے سب ہوک شفٹ ہو جاتے ہیں — ان کی اسٹیٹ مکس جاتی ہے۔ ESLint قاعدہ hooks/exhaustive-deps اس بارے میں انتباہ کرتا ہے۔
useLayoutEffect مطابقتی ہے اور براؤزر کے تبدیلیاں پینٹ کرنے سے پہلے چلتا ہے۔ useEffect غیر مطابقتی ہے — پینٹنگ کے بعد۔ useLayoutEffect کو صرف اس وقت استعمال کریں جب آپکو صرف کرنے والے کو تبدیلیاں دیکھنے سے پہلے DOM کو ناپنے یا بدلنے کی ضرورت ہو (popover پزیشن، اسکرول بحالی)۔
useEffect کے اندر AbortController استعمال کریں۔ ایک controller بنائیں، signal کو fetch میں پاس کریں، اور صفائی فنکشن میں controller.abort() کال کریں۔ پرانے براؤزرز کے لیے، ایک cancelled فلیگ استعمال کریں: return () => { cancelled = true; } setState سے پہلے ایک جانچ کے ساتھ۔
کسٹم ہوک ایک JavaScript فنکشن ہے جس کا use سابقہ ہے جو مضمن ہوک استعمال کرتا ہے۔ اسے تب بنائیں جب ہوک کے ساتھ وہی لاجک دو یا زیادہ کمپونینٹس میں دوہرایا جاتا ہے۔ مثالیں: useDebounce, useLocalStorage, useMediaQuery۔ کسٹم ہوک HOC اور render props کی جگہ لےتے ہیں۔
Strict Mode میں، React جان بوجھ کر ڈیویلپمنٹ میں صفائی نہ کیئے گئے افیکٹس کے ساتھ بگز ڈھونک کے لیے کمپونینٹ کو ایرادہً دو بار ماؤنٹ اور ان ماؤنٹ کرتا ہے۔ اگر صفائی صحیح طور پر لیکھی گئی ہے، تو دوہرا کال کوئی مسئلہ پیدا نہیں کرتا۔ پروڈکشن موڈ میں ایسا نہیں ہوتا۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں