Daraja 3 β Hooks olami¶
β¬ οΈ Oldingi: Daraja 2 β Interaktivlik: State va Events Β· π README Β· Keyingi: Daraja 4 β Formalar va ma'lumotlar β‘οΈ
Hook'lar β komponentlarga "qo'shimcha kuch" beruvchi funksiyalar (use bilan boshlanadi). useStateni allaqachon ko'rdik.
Hooks qoidalari (buzmaslik shart!): 1. Hook'larni faqat komponent yoki boshqa hook ichida, eng yuqori darajada chaqiring. 2.
if,for, funksiya ichida hook chaqirmang β har doim bir xil tartibda chaqirilishi kerak.
3.1. useEffect β side effect'lar¶
useEffect β render'dan tashqaridagi ishlar uchun: tarmoq so'rovi, taymer, brauzer API'lari, obuna (subscription).
β οΈ 2026-yilning eng muhim darsi:
useEffectβ bu oxirgi chora, "to'g'ri yo'l" emas! Ko'p odam uni ma'lumot olishga ishlatadi β bu eski (2020) pattern. Zamonaviy yondashuvni Daraja 6 (TanStack Query) va Daraja 11 (Server Components)'da ko'rasiz. Hozir esauseEffectni tushunish uchun o'rganamiz.
import { useState, useEffect } from "react";
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setSeconds((s) => s + 1);
}, 1000);
// Cleanup β komponent yo'qolganda taymerni tozalaymiz
return () => clearInterval(id);
}, []); // [] = faqat bir marta (mount'da) ishlasin
return <p>{seconds} soniya o'tdi</p>;
}
Dependency array (eng muhim qism)¶
Quyidagi diagramma effect'ning to'liq hayot siklini ko'rsatadi β mount'da ishlaydi, deps o'zgarsa avval cleanup keyin qayta ishlaydi, unmount'da oxirgi marta tozalanadi:
useEffect(() => { ... }); // har renderdan keyin (kamdan-kam kerak)
useEffect(() => { ... }, []); // faqat bir marta (mount)
useEffect(() => { ... }, [userId]); // userId o'zgarganda
Strict Mode'da
useEffect2 marta ishlaydi (development'da) β bu xato emas, cleanup'ingiz to'g'ri ekanini tekshirish uchun. Production'da 1 marta ishlaydi.
Qachon useEffect KERAK EMAS?¶
// β Kerak emas β derived state (hosilaviy qiymat)
const [fullName, setFullName] = useState("");
useEffect(() => {
setFullName(first + " " + last);
}, [first, last]);
// β
To'g'risi β render paytida hisoblang
const fullName = first + " " + last;
3.2. useRef β DOM va o'zgarmas qiymat¶
Ikki vazifasi bor: (1) DOM elementiga murojaat, (2) render'lar orasida qiymat saqlash (o'zgarsa ham re-render qilmaydi).
import { useRef } from "react";
function FocusInput() {
const inputRef = useRef(null);
const focus = () => {
inputRef.current.focus(); // DOM'ga to'g'ridan-to'g'ri
};
return (
<>
<input ref={inputRef} />
<button onClick={focus}>Fokus qil</button>
</>
);
}
// Render orasida qiymat saqlash (re-render qilmasdan)
function Stopwatch() {
const countRef = useRef(0);
countRef.current += 1; // o'zgaradi, lekin re-render bo'lmaydi
}
React 19 yangiligi: endi
refni oddiy prop sifatida uzata olasiz βforwardRefkerak emas:
3.3. useContext β "prop drilling"dan qutulish¶
Ma'lumotni komponentlar daraxti bo'ylab har qatlamga props uzatmasdan tarqatish.
Quyidagi diagramma "prop drilling" (har qatlam orqali prop uzatish) bilan Context Provider/useContext yondashuvini yonma-yon solishtiradi:
import { createContext, useContext, useState } from "react";
// 1. Context yaratish
const ThemeContext = createContext();
// 2. Provider bilan o'rash
function App() {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Toolbar />
</ThemeContext.Provider>
);
}
// 3. Istalgan chuqurlikda ishlatish
function Toolbar() {
return <ThemedButton />; // theme'ni props sifatida uzatish shart emas
}
function ThemedButton() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
Hozirgi: {theme}
</button>
);
}
Muhim: Context β bu state manager emas, balki dependency injection mexanizmi. Tez-tez o'zgaradigan ma'lumot uchun (har soniya) ishlatmang β performance muammosi chiqaradi. Buni Daraja 6'da ko'ramiz.
3.4. useReducer β murakkab state mantig'i¶
State logikasi murakkablashganda (ko'p maydon, ko'p action), useState o'rniga useReducer. Redux'ning kichik versiyasi.
Quyidagi diagramma useReducer oqimini ko'rsatadi: dispatch(action) reducer'ga boradi, reducer yangi state qaytaradi va komponent qayta render bo'ladi:
import { useReducer } from "react";
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case "increment": return { count: state.count + 1 };
case "decrement": return { count: state.count - 1 };
case "reset": return { count: 0 };
default: return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>{state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
<button onClick={() => dispatch({ type: "reset" })}>Reset</button>
</div>
);
}
Qachon
useReducer? Multi-step forma, murakkab UI holatlari, bir-biriga bog'liq state'lar. DDD analogiyasi: reducer β sof funksiya,actionβ domain event kabi.
3.5. useMemo va useCallback β memoizatsiya¶
Qimmat hisob-kitobni yoki funksiyani keraksiz qayta yaratmaslik uchun.
Quyidagi diagramma memoizatsiya mantig'ini ko'rsatadi: deps o'zgarmasa natija keshdan olinadi, faqat deps o'zgarganda qayta hisoblanadi:
import { useMemo, useCallback } from "react";
function App({ items, filter }) {
// Faqat items yoki filter o'zgarganda qayta hisoblanadi
const filtered = useMemo(() => {
return items.filter((i) => i.includes(filter));
}, [items, filter]);
// Funksiya identifikatorini saqlaydi (child re-render'ini oldini olish)
const handleClick = useCallback(() => {
console.log("bosildi");
}, []);
return <Child onClick={handleClick} data={filtered} />;
}
β οΈ 2026 muhim yangilik β React Compiler: React 19 bilan kelgan compiler memoizatsiyani avtomatik qiladi. Ya'ni kelajakda
useMemo/useCallbackni qo'lda yozish kamayadi. Lekin ularni tushunish kerak β eski kod va compiler yo'q joylarda hali ham ishlatiladi. Maslahat: premature optimization qilmang β avval profiling, keyin memo.
3.6. Custom hooks β o'z hook'ingizni yozish¶
Takrorlanuvchi mantiqni qayta ishlatiladigan funksiyaga ajrating. use bilan boshlansa bo'ldi.
// useToggle.js
import { useState } from "react";
function useToggle(initial = false) {
const [value, setValue] = useState(initial);
const toggle = () => setValue((v) => !v);
return [value, toggle];
}
// Ishlatish:
function Modal() {
const [isOpen, toggle] = useToggle();
return (
<>
<button onClick={toggle}>{isOpen ? "Yopish" : "Ochish"}</button>
{isOpen && <div>Modal oynasi</div>}
</>
);
}
Ko'proq foydali custom hook:
// useLocalStorage.js
import { useState, useEffect } from "react";
function useLocalStorage(key, initial) {
const [value, setValue] = useState(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initial;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
Bu β React'da kodni qayta ishlatishning eng kuchli usuli. Custom hooks orqali siz o'z "kutubxonangizni" yasaysiz. Backend'dagi Service/Repository pattern'iga o'xshash β mantiqni komponentdan ajratadi.
3.7. Keng tarqalgan xatolar¶
| Xato | To'g'risi |
|---|---|
useEffectni ma'lumot olishga "asosiy yo'l" deb ishlatish |
TanStack Query / RSC (Daraja 6, 11) |
Dependency array'ni unutish ([] qo'ymaslik) |
Cheksiz loop'ga olib keladi |
| Effect ichida cleanup qilmaslik (taymer, listener) | return () => {...} |
if ichida hook chaqirish |
Faqat top-level |
Hamma joyga useMemo/useCallback (premature) |
Avval profiling |
Derived state'ni useEffect+useState bilan |
Render paytida hisoblash |
+20 Masala β Daraja 3¶
Oson (useEffect, useRef):
1. Sahifa ochilganda console.log("Mount!") chiqaring (effect, []).
2. Har soniya o'sadigan taymer yarating (cleanup bilan).
3. Input'ga avtomatik fokus bering (useRef, mount'da).
4. State o'zgarganda document.titleni yangilang.
5. Tugmaning necha marta bosilganini useRef'da saqlang (re-render qilmasdan).
6. 5 soniyalik countdown taymer yarating (0 da to'xtasin).
7. Oyna o'lchami (window.innerWidth)ni real vaqtda ko'rsating (resize listener + cleanup).
8. Toggle qiluvchi tugma yarating (ochiq/yopiq).
O'rta (useContext, useReducer, custom hook):
9. Theme switcher: useContext bilan light/dark rejim (butun ilovaga).
10. useToggle custom hook'ini yozing va modal'da ishlating.
11. useLocalStorage hook'ini yozing va todo ro'yxatini saqlang.
12. Savatchani useReducer bilan boshqaring (ADD, REMOVE, CLEAR).
13. useReducer bilan multi-step forma holati.
14. useFetch custom hook'ini yozing (loading, error, data qaytarsin).
15. useDebounce hook'ini yozing va qidiruv inputida ishlating.
Qiyin:
16. useWindowSize, usePrevious, useOnlineStatus β 3 ta custom hook yozing.
17. Auth kontekstini quring: login, logout, user β useContext + useReducer.
18. Stopwatch: start/stop/reset, lap vaqtlari (useRef + useState kombinatsiyasi).
19. useMemo bilan: 10000 elementli ro'yxatni filterlash (performance farqini sezing).
20. Infinite scroll mantiqi: scroll oxiriga yetganda yangi ma'lumot yuklash (useRef + useEffect + IntersectionObserver).
β Qiyin masalalar yechimi (16β20)
16 β 3 ta custom hook:
function useWindowSize() {
const [size, setSize] = useState({ w: window.innerWidth, h: window.innerHeight });
useEffect(() => {
const onResize = () => setSize({ w: window.innerWidth, h: window.innerHeight });
window.addEventListener("resize", onResize);
return () => window.removeEventListener("resize", onResize); // cleanup SHART
}, []);
return size;
}
function usePrevious(value) {
const ref = useRef();
useEffect(() => { ref.current = value; }, [value]); // render'dan keyin yangilanadi
return ref.current; // shuning uchun "oldingi" qiymatni qaytaradi
}
function useOnlineStatus() {
const [online, setOnline] = useState(navigator.onLine);
useEffect(() => {
const on = () => setOnline(true), off = () => setOnline(false);
window.addEventListener("online", on);
window.addEventListener("offline", off);
return () => { window.removeEventListener("online", on); window.removeEventListener("offline", off); };
}, []);
return online;
}
17 β Auth (useContext + useReducer):
const AuthContext = createContext(null);
function authReducer(state, action) {
switch (action.type) {
case "login": return { user: action.user };
case "logout": return { user: null };
default: return state;
}
}
function AuthProvider({ children }) {
const [state, dispatch] = useReducer(authReducer, { user: null });
const login = (user) => dispatch({ type: "login", user });
const logout = () => dispatch({ type: "logout" });
return (
<AuthContext.Provider value={{ user: state.user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = () => useContext(AuthContext); // qulay custom hook
18 β Stopwatch (useRef interval uchun, cleanup bilan):
function Stopwatch() {
const [ms, setMs] = useState(0);
const [yurib, setYurib] = useState(false);
const intervalRef = useRef(null);
useEffect(() => {
if (yurib) intervalRef.current = setInterval(() => setMs((m) => m + 10), 10);
return () => clearInterval(intervalRef.current); // har safar tozalanadi
}, [yurib]);
return (
<div>
<p>{(ms / 1000).toFixed(2)}s</p>
<button onClick={() => setYurib(true)}>Start</button>
<button onClick={() => setYurib(false)}>Stop</button>
<button onClick={() => { setYurib(false); setMs(0); }}>Reset</button>
</div>
);
}
19 β useMemo bilan filtrlash (qimmat hisobni keshlash):
function BigList({ items, query }) {
const filtered = useMemo(
() => items.filter((it) => it.toLowerCase().includes(query.toLowerCase())),
[items, query] // faqat shular o'zgarsa qayta hisoblanadi
);
return <ul>{filtered.map((it, i) => <li key={i}>{it}</li>)}</ul>;
}
20 β Infinite scroll (IntersectionObserver β yo'nalish):
function useInfiniteScroll(onReachEnd) {
const sentinelRef = useRef(null);
useEffect(() => {
const obs = new IntersectionObserver(
([entry]) => { if (entry.isIntersecting) onReachEnd(); }
);
if (sentinelRef.current) obs.observe(sentinelRef.current);
return () => obs.disconnect();
}, [onReachEnd]);
return sentinelRef; // ro'yxat oxiridagi bo'sh <div ref={sentinelRef}/> ga ulanadi
}
onReachEnd chaqiriladi (yangi sahifa yuklanadi). scroll event'dan tozaroq va tezroq.