Daraja 6 β State management¶
β¬ οΈ Oldingi: Daraja 5 β Routing (React Router v7) Β· π README Β· Keyingi: Daraja 7 β Performance optimizatsiya β‘οΈ
Ilova kattalashganda state'ni boshqarish murakkablashadi. 2026-yilning eng muhim qoidasi: server state va client state'ni ajrating.
| Tur | Nima | Yechim |
|---|---|---|
| Server state | API'dan kelgan ma'lumot (cache, sync kerak) | TanStack Query |
| Client state | UI holati (modal, theme, forma) | Zustand / useState / Context |
| Katta enterprise | Murakkab global state | Redux Toolkit |
β οΈ Eng keng tarqalgan xato: API javobini Redux/Zustand'ga saqlash. Buni qilmang β server state uchun TanStack Query bor. Bu ikkisini aralashtirmaslik kod sifatini keskin oshiradi.
Quyidagi diagramma bu ikki turning farqini va TanStack Query keshi qanday yashashini (fetch β cache β stale β refetch) ko'rsatadi:
6.1. TanStack Query (server state uchun)¶
API ma'lumotini boshqarishning eng yaxshi yo'li. Caching, background refetch, loading/error β hammasi avtomatik.
import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<Users />
</QueryClientProvider>
);
}
function Users() {
const { data, isLoading, error } = useQuery({
queryKey: ["users"],
queryFn: () =>
fetch("https://jsonplaceholder.typicode.com/users").then((r) => r.json()),
});
if (isLoading) return <p>Yuklanmoqda...</p>;
if (error) return <p>Xato!</p>;
return <ul>{data.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
}
Solishtiring: Daraja 4'dagi
useEffectversiyasi 25 qator edi. Bu yerda 5 qator β va ustiga caching, refetch, deduplication bepul keladi. Aynan shu β to'g'ri yo'l.
Mutation (ma'lumot o'zgartirish):
import { useMutation, useQueryClient } from "@tanstack/react-query";
function AddUser() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (newUser) =>
fetch("/api/users", { method: "POST", body: JSON.stringify(newUser) }),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["users"] }); // qayta yuklash
},
});
return <button onClick={() => mutation.mutate({ name: "Ali" })}>Qo'shish</button>;
}
6.2. Zustand (client state uchun)¶
Eng yengil va sodda global state. Redux'siz boilerplate.
import { create } from "zustand";
// Store yaratish
const useCartStore = create((set) => ({
items: [],
addItem: (item) => set((state) => ({ items: [...state.items, item] })),
removeItem: (id) =>
set((state) => ({ items: state.items.filter((i) => i.id !== id) })),
clear: () => set({ items: [] }),
}));
// Istalgan komponentda β Provider kerak emas!
function Cart() {
const { items, removeItem } = useCartStore();
return (
<ul>
{items.map((i) => (
<li key={i.id}>
{i.name} <button onClick={() => removeItem(i.id)}>x</button>
</li>
))}
</ul>
);
}
function AddButton() {
const addItem = useCartStore((s) => s.addItem); // faqat kerakli qismni oling
return <button onClick={() => addItem({ id: 1, name: "Kitob" })}>Qo'shish</button>;
}
Zustand'ning afzalligi:
<Provider>o'rash shart emas, selector ((s) => s.addItem) bilan faqat kerakli qismga obuna bo'lasiz β kamroq re-render. Auth, theme, savatcha β shular uchun ideal.
6.3. Redux Toolkit (katta loyihalar uchun)¶
Murakkab, ko'p jamoali enterprise loyihalarda. Strukturali, DevTools kuchli.
import { createSlice, configureStore } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: "counter",
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1; }, // Immer ichida β mutatsiya OK
decrement: (state) => { state.value -= 1; },
},
});
export const { increment, decrement } = counterSlice.actions;
export const store = configureStore({ reducer: { counter: counterSlice.reducer } });
Qachon Redux? Faqat haqiqatan murakkab, ko'p o'zaro bog'liq global state bo'lsa. Aks holda Zustand + TanStack Query yetadi. Premature'ga Redux qo'shmang.
6.4. Qanday tanlash kerak? (qaror jadvali)¶
- Faqat bitta komponent ichida β
useState - Bir nechta komponent (kichik daraxt) β lifting state up yoki Context
- Tez-tez o'zgaradigan global UI state β Zustand
- API ma'lumoti β TanStack Query (har doim!)
- Juda katta, murakkab enterprise β Redux Toolkit + TanStack Query
6.5. Keng tarqalgan xatolar¶
| Xato | To'g'risi |
|---|---|
| API javobini Redux/Zustand'ga saqlash | TanStack Query |
| Hamma narsani global state'ga tiqish | Avval local, keyin ko'taring |
| Context'ni tez-tez o'zgaruvchi state uchun ishlatish | Zustand (selectorlar bilan) |
| Boshlanishidayoq Redux qo'shish | Avval sodda yechim |
queryKeyni noto'g'ri tuzish |
Aniq, izchil kalitlar |
+20 Masala β Daraja 6¶
Oson (TanStack Query):
1. useQuery bilan foydalanuvchilarni yuklang.
2. Loading va error holatlarini chiroyli ko'rsating.
3. "Refetch" tugmasi qo'shing.
4. queryKeyga parametr bering (["user", id]) va bitta foydalanuvchini oling.
5. staleTime sozlang va caching ishini kuzating.
6. Ikki xil API'dan ma'lumotni parallel yuklang.
7. enabled opsiyasi bilan shartli so'rov (faqat id bor bo'lsa).
8. DevTools'ni o'rnating va cache'ni kuzating.
O'rta (Zustand + mutation):
9. Zustand bilan savatcha: qo'shish/o'chirish/tozalash.
10. Zustand bilan dark mode toggle (butun ilovaga).
11. Auth store: login, logout, user (Zustand).
12. useMutation bilan yangi post qo'shish + invalidateQueries.
13. Optimistik mutation (TanStack Query): like'ni darhol ko'rsatish.
14. Selector bilan Zustand'dan faqat kerakli qismni olib re-render'ni kamaytiring.
15. Pagination: page state + useQuery (keepPreviousData).
Qiyin:
16. To'liq CRUD ilovasi: TanStack Query (read) + mutations (create/update/delete).
17. Infinite scroll: useInfiniteQuery bilan.
18. Server state (TanStack Query) + client state (Zustand)ni bitta ilovada to'g'ri ajrating.
19. Redux Toolkit bilan counter + todo slice yarating.
20. EduCore prototipi: tenant ma'lumotini TanStack Query bilan, UI holatini Zustand bilan boshqaring.
β Qiyin masalalar yechimi (16β20)
16 β TanStack Query CRUD (read + mutation + invalidate):
function useStudents() {
return useQuery({
queryKey: ["students"],
queryFn: () => fetch("/api/students").then((r) => r.json()),
});
}
function useAddStudent() {
const qc = useQueryClient();
return useMutation({
mutationFn: (s) => fetch("/api/students", { method: "POST", body: JSON.stringify(s) }).then((r) => r.json()),
onSuccess: () => qc.invalidateQueries({ queryKey: ["students"] }), // ro'yxat avtomatik yangilanadi
});
}
18 β Server state vs client state ajratish:
// SERVER state β TanStack Query (backend'dan keladi, kesh, qayta yuklash)
const { data: students } = useStudents();
// CLIENT state β Zustand (faqat UI: modal ochiq/yopiq, sidebar)
const useUiStore = create((set) => ({
sidebarOpen: false,
toggleSidebar: () => set((s) => ({ sidebarOpen: !s.sidebarOpen })),
}));
19 β Redux Toolkit (counter + todo slice):
const counterSlice = createSlice({
name: "counter",
initialState: { value: 0 },
reducers: {
increment: (s) => { s.value += 1; }, // Immer tufayli "mutatsiya" xavfsiz
decrement: (s) => { s.value -= 1; },
},
});
const todoSlice = createSlice({
name: "todos",
initialState: { items: [] },
reducers: {
add: (s, a) => { s.items.push({ id: Date.now(), text: a.payload }); },
remove: (s, a) => { s.items = s.items.filter((t) => t.id !== a.payload); },
},
});
const store = configureStore({
reducer: { counter: counterSlice.reducer, todos: todoSlice.reducer },
});
(20 β EduCore prototipi:
useQuery(["tenant", id])bilan tenant ma'lumoti + Zustand'da UI holati β 16 va 18 ni birlashtirish.)