React Hookları — siniflər yazmadan funksional komponentlərdə vəziyyət, effektlər, kontekst və React-in digər imkanlarından istifadə etməyə imkan verən funksiyalardır. React 16.8-də təqdim edilən hooklar, HOC və render props kimi mürəkkəb naxışları əvəz edərək proqramlaşdırmaya yanaşmanı köklü şəkildə dəyişdi. React, 2024-ə görə, komponentin idarə edilməsinin bütün ssenarilərini əhatə edən 15 daxili hook var.
Başlıca
React Hookları — siniflər yaratmadan çərçivənin daxili mexanizmlərinə „qoşulmağa” imkan verən React-in daxili funksiyalar toplusudur. React 16.8-dən əvvəl funksional komponentlər yalnız props qəbul edə və JSX qaytara bilirdi — istənilən mürəkkəb məntiq sinif komponenti tələb edirdi.
Sinif komponentlərinin problemi — əlaqəli məntiqin ayrılması. Bir varlığa aid kod (məsələn, WebSocket abunəliyi) məcburi şəkildə componentDidMount, componentDidUpdate və componentWillUnmount arasında bölünürdü. Hooklar bunu həll edir: bütün məntiq bir useEffect-də qruplaşdırılır.
Ikinci problem — məntiqin təkrar istifadəsi. Sinif komponentləri arasında vəziyyət məntiqini təkrar istifadə etmək üçün HOC (yüksək səviyyəli komponentlər) və ya render props tətbiq etmək lazım idi — hər iki naxış komponent ağacında əlavə iç-içəlik yaradırdı. Xüsusi hooklar bu problemi iç-içəlik olmadan həll edir.
useState — ən əsas hook. Ilkin dəyər qəbul edir və kortej qaytarır: cari dəyər və onu yeniləmək üçün funksiya. Siniflərdəki this.setState-dən fərqli olaraq, useState obyektləri birləşdirmir — yeni vəziyyət müəyyən useState çağırışı üçün əvvəlki vəziyyəti tamamilə əvəz edir.
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-in setteri əvvəlki dəyəri alan və yenisini qaytaran funksiya qəbul edə bilər. Funksional forma yeni vəziyyət əvvəlkindən hesablandıqda və setState-in toplu çağırışları mümkün olduqda məcburidir — hər çağırış aktual əvvəlki dəyəri alacaq.
useEffect — funksional komponentlərdə yan təsirləri yerinə yetirmək üçün hook. Iki arqument qəbul edir: effekt funksiyası və asılılıq massivi. React effekti hər renderdən sonra yerinə yetirir, lakin asılılıqlar göstərildikdə — yalnız onlardan hər hansı biri dəyişdikdə.
Boş asılılıq massivi [] effektin ilk renderdən sonra bir dəfə yerinə yetirildiyini bildirir (componentDidMount-un analoqu). Effektdən funksiya qaytarmaq təmizləmədir (cleanup), bu, komponent silinəndə (componentWillUnmount-un analoqu) və effekt yenidən yerinə yetirilməzdən əvvəl işləyir.
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)]);
};
// Cleanup - soketi bağla
return () => socket.close();
}, [roomId]);
return <ul>
{messages.map((msg, i) =>
<li key={i}>{msg.text}</li>
)}
</ul>;
}
useEffect-in asılılıqları — effektlə xarici dünya arasında yeganə əlaqədir. Effektdə props və ya vəziyyətdən dəyişən istifadə edilirsə, o, asılılıq massivində olmalıdır. Bu qaydaya məhəl qoymamaq köhnəlmiş məlumatlarla (stale closure) bağlı səhvlərin mənbəyidir.
useContext — kontekst dəyərini oxumaq üçün hook. React.createContext ilə yaradılmış kontekst obyektini qəbul edir və cari dəyəri qaytarır. Kontekst dəyişərsə, komponent avtomatik olaraq yeni dəyərlə yenidən render edilir.
useContext yaranana qədər funksional komponentlərdə kontekstə giriş Context.Consumer-də örtük tələb edirdi, bu da iç-içəlik yaradırdı. useContext Consumer-ı tamamilə aradan qaldırır — hook-u funksional komponentin istənilən yerində çağırmaq kifayətdir.
import React, { createContext, useContext } from 'react';
const ThemeContext = createContext('açıq');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button
className={`btn btn-${theme}`}
>
{theme === 'dark' ? 'moon' : '☀️'}
</button>;
}
useContext Redux və ya qlobal vəziyyətin əvəzi deyil. React kontekstdən nadir dəyişən dəyərlər üçün istifadə etməyi tövsiyə edir — mövzu, dil, icazə. Tez-tez yenilənən məlumatlar üçün hər yenidən render kontekstin bütün istehlakçılarını yenidən hesablayacaq, bu da performansı aşağı sala bilər.
useReducer — mürəkkəb yeniləmə məntiqi olan vəziyyətlər üçün useState-ə alternativdir. Reducer funksiyası və ilkin vəziyyət qəbul edir, cari vəziyyət və dispatch funksiyası qaytarır. Reducer cari vəziyyət və aksiyanı qəbul edir, yeni vəziyyət qaytarır — yan təsirləri olmayan təmiz funksiya.
useReducer xüsusilə bir neçə aksiya (set, reset, increment, addItem) bir vəziyyəti idarə etdikdə faydalıdır. Müxtəlif setterlərlə bir neçə useState əvəzinə — aydın aksiya tipləri ilə bir reducer. Bu, məntiqi proqnozlaşdırıla bilən və asanlıqla test edilə bilən edir.
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 renderlər arasında qorunan dəyişik obyekt yaradır. current-in dəyişməsi yenidən renderə səbəb olmur. Əsas tətbiqi — DOM elementlərinə giriş və dəyişik dəyərlərin saxlanması (taymerlər, əvvəlki dəyərlər, kitabxana nüsxələri).
useMemo funksiyanın nəticəsini yadda saxlayır. Dəyəri yalnız asılılıqlardan biri dəyişdikdə yenidən hesablayır. Bahalı hesablamalar üçün istifadə edin — böyük massivlərin filtrasiyası, sıralanması, məlumatların formatlaşdırılması. useCallback — funksiyaların yadda saxlanması üçün useMemo-nun xüsusi halı.
import React, { useRef, useMemo, useCallback } from 'react';
function SearchPage({ items, query, onItemSelect }) {
const inputRef = useRef(null);
// Quraşdırarkən avtofokus
useEffect(() => {
inputRef.current?.focus();
}, []);
// Filtrə edilmiş nəticəni yadda saxla
const filtered = useMemo(() => {
return items.filter(item =>
item.name.toLowerCase()
.includes(query.toLowerCase())
);
}, [items, query]);
// Callback-i yadda saxla
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>
);
}
Vacib qayda: useRef, useMemo və useCallback — optimallaşdırma alətləridir, məcburi konstruksiyalar deyil. Hər şeyi useMemo ilə örtməyin — əvvəlcə performansı ölçün. Vaxtından əvvəl optimallaşdırma kodu çətinləşdirir. React komponentləri tez render edir; useMemo yalnız hesablamalar həqiqətən bahalı olduqda lazımdır (O(n²) və yuxarı).
React hooklar üçün iki sərt qayda təqdim etdi. Birinci: hookları yalnız yuxarı səviyyədə çağırın — şərtlərin, dövrlərin və ya iç-içə funksiyaların daxilində deyil. Ikinci: hookları yalnız React funksional komponentlərindən və ya xüsusi hooklardan çağırın. ESLint-plugin eslint-plugin-react-hooks avtomatik olaraq hər iki qaydanı yoxlayır.
Ən tez-tez edilən səhv — hookların çağırılma ardıcıllığının pozulması. React renderlər arasında hookların çağırılma ardıcıllığına etibar edir. Hook şərt daxilindədirsə və renderlərdən birində çağırılmayıbsa, bütün sonrakı hooklar sürüşür — bu da səhvlərə səbəb olur.
| Səhv | Nə baş verir | Həlli |
|---|---|---|
| Şərtdə hook | Hookların sırası pozulur | Şərtin məntiqini hookun içinə köçürün |
| Stale closure | Effekt köhnə dəyərdən istifadə edir | Bütün asılılıqları massivə əlavə edin |
| Sonsuz dövr | Asılılıqları olmayan useEffect vəziyyəti dəyişir | Asılılıqları göstərin və ya useReducer istifadə edin |
| Renderdə ref-in dəyişdirilməsi | Funksiya gövdəsində yan təsir | Mutasiyaları useEffect-ə köçürün |
Ikinci tez-tez edilən səhv — useEffect-də stale closure. Effektdə asılılıqlarda göstərilməyən dəyişən istifadə edilirsə, effekt bağlanma anındakı dəyəri „tutur”. Həlli — istifadə olunan bütün dəyişənləri həmişə asılılıq massivinə daxil edin. Asılılıqlar çox olarsa, effekti bir neçə hissəyə bölmək olar.
Tez-tez verilən suallar
React hookların çağırılma ardıcıllığına etibar edir renderlər arasında. Hook şərt daxilində çağırılıbsa və renderlərdən birində işləməyibsə, bütün sonrakı hooklar „sürüşür” — onların vəziyyəti qarışır. ESLint qaydası hooks/exhaustive-deps bu barədə xəbərdarlıq edir.
useLayoutEffect sinxrondur və brauzer dəyişiklikləri çəkməzdən əvvəl yerinə yetirilir. useEffect asinxrondur — çɘkimdən sonra. useLayoutEffect yalnız istifadəçi dəyişiklikləri görməzdən əvvəl DOM-u ölçmək və ya dəyişmək lazım olduqda istifadə edin (popover mövqeyi, scroll restoration).
useEffect daxilində AbortController istifadə edin. Controller yaradın, signal-ı fetch-ə ötürün və cleanup funksiyasında controller.abort() çağırın. Köhnə brauzerlər üçün cancelled bayrağı uyğundur: return () => { cancelled = true; } setState-dən əvvəl yoxlama ilə.
Xüsusi hook — use prefiksi ilə JavaScript funksiyası, daxili hooklardan istifadə edir. Eyni hook məntiqi iki və ya daha çox komponentdə təkrarlananda yaradın. Nümunələr: useDebounce, useLocalStorage, useMediaQuery. Xüsusi hooklar HOC və render props-u əvəz edir.
Strict Mode-da React təmizlənməmiş effektlərlə bağlı səhvləri tapmaq üçün tərtibat rejimində qəsdən komponenti iki dəfə mont edir və silir. Cleanup düzgün yazılıbsa, ikiqat çağırış problem yaratmır. İstehsal rejimində bu baş vermir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun