Mundarija (33)
- Bu darsda
- 1. Nega bu kerak?
- 2. React cache()
- 2.1 Qanday yoziladi
- 2.2 cache() va "use cache"
- 2.3 Natija oynasida: client'da cache() eslamaydi
- 2.4 So'rov doirasi: o'quv modeli
- 3. Kanon o'lchovi: 4 dan 2 ga
- 3.1 Tajriba
- 3.2 Raqamlarni o'qish
- 3.3 fetch uchun bu o'zi bor
- 4. Data Access Layer
- 4.1 Muammo: ma'lumot hamma joyda
- 4.2 Naqsh
- 4.3 Kanon dal.ts
- 4.4 Natija oynasida: DTO
- 4.5 server-only — qo'riqchi
- 4.6 Ruxsat tekshiruvi ma'lumot yonida
- 4.7 Hujjatdagi qo'shimcha himoya: taint
- 5. generateMetadata va DAL
- 6. cache() tuzoqlari
- 7. Portfolio qadami: DAL va commit
- 7.1 Fayllar
- 7.2 Tekshiruv va commit
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): qaysi biri?
- 2-mashq (o'rta): foydalanuvchi DTO'si
- 3-mashq (qiyin): so'rov doirasidagi memo
- 4-mashq: Portfolio qadami
- 10. Real ishda
- Xulosa
- Manbalar
React cache() va Data Access Layer: Next.js'da ma'lumot qatlami
Qisqacha:
cache()— React funksiyasi: u o'ralgan funksiyaning natijasini bitta server so'rovi (render) davomida eslab qoladi.generateMetadatava sahifa bir xil postni so'rasa, haqiqiy o'qish bir marta bo'ladi. Keyingi so'rovda xotira toza — bu"use cache"emas, u so'rovlararo kesh. Data Access Layer (DAL — ma'lumotga murojaat qatlami) — sahifalar ma'lumotni faqat bitta server modulidan oladigan naqsh. Bu modulserver-onlybilan himoyalangan, ruxsat tekshiruvi ma'lumot yonida turadi va sahifaga faqat kerakli maydonlar — DTO qaytariladi.
Bu darsda
cache()bilan"use cache"farqini aniq aytasiz: bitta so'rov va ko'p so'rov.- Kanon o'lchovida
cache()chaqiruvlarni 4 dan 2 ga tushirganini va qachon foydasiz ekanini tushuntirasiz. - Natija oynasida
cache()ning client'dagi xulqini o'zingiz ko'rasiz (u yerda u hech narsani eslamaydi). dal.tsyozasiz:server-only,cache(), DTO — va ruxsat tekshiruvi qayerga qo'yilishini bilasiz.portfolioga DAL va loyiha/post sahifalarigagenerateMetadataqo'shib, holat 20 ni commit qilasiz.
Oldin bilishingiz kerak: Serverda ma'lumot olish, Cache Components I, Server va Client kompozitsiyasi, Memoizatsiya, Frontend xavfsizligi React'da.
1. Nega bu kerak?
Blog posti sahifasini oching. Unga ikki joyda post ma'lumoti kerak:
generateMetadata— brauzer tabidagi sarlavha va Google uchun tavsif (<title>,<meta name="description">).- Sahifaning o'zi — post matni.
Ikkalasi alohida funksiya. Ikkalasi ham post(slug) ni chaqiradi. Demak bitta sahifa uchun fayl ikki marta o'qiladi. Bazadan bo'lsa — ikki marta so'rov. Sahifada post muallifi bloki, "o'xshash postlar" bloki bo'lsa — yana ikki marta.
Props bilan uzatish mumkin edi, lekin generateMetadata va sahifa bir-biriga prop bera olmaydi — ularni Next.js alohida chaqiradi.
Choyxonadagi buyurtmani eslang. Bitta stol ofitsiantga uch marta "bitta choynak choy" desa, ofitsiant uch choynak olib kelmaydi — u bu bitta stolning bitta buyurtmasi ekanini biladi. Boshqa stol esa o'z choynagini oladi. cache() — shu ofitsiant: bitta so'rov ichidagi bir xil chaqiruvlarni birlashtiradi.
2. React cache()
2.1 Qanday yoziladi
cache — react paketidan. Funksiyani o'raysiz, o'ralganini ishlatasiz:
import { cache } from "react";
import { post } from "./blog";
export const postniOl = cache(async (slug: string) => post(slug));Endi bitta render davomida:
postniOl("salom")birinchi marta —post("salom")ishlaydi, natija eslab qolinadi;postniOl("salom")ikkinchi marta — o'sha natija (o'sha Promise) qaytadi,postishlamaydi;postniOl("xayr")— boshqa argument, alohida chaqiruv.
Argumentlar Object.is bilan solishtiriladi: satr va son qiymat bo'yicha, obyekt esa havola bo'yicha. postniOl({ slug: "salom" }) ni ikki marta yozsangiz — ikkita har xil obyekt, ikkita chaqiruv. Shuning uchun cache() ga oddiy qiymatlar (satr, son) bering.
2.2 cache() va "use cache"
Nomlari o'xshash, vazifasi boshqa:
React cache() |
"use cache" |
|
|---|---|---|
| Qancha yashaydi | Bitta so'rov (render) | cacheLife muddatigacha |
| Kimga umumiy | Faqat shu so'rovga | Hamma foydalanuvchiga |
| Qayerda saqlanadi | So'rov xotirasida | Server keshida, statik qobiqda |
| Nima uchun | Takroriy chaqiruvni birlashtirish | Qayta hisoblamaslik, tez sahifa |
| Foydalanuvchiga xos ma'lumot | Mumkin (so'rov tugashi bilan o'chadi) | Taqiqlangan (cookies() — xato) |
Oxirgi qator muhim. cache() bilan joriy foydalanuvchini o'qish xavfsiz: natija boshqa foydalanuvchiga hech qachon o'tmaydi. Next.js hujjatidagi DAL misoli aynan shunday — getCurrentUser = cache(async () => { … cookies() … }).
2.3 Natija oynasida: client'da cache() eslamaydi
cache() faqat Server Component muhitida ishlaydi. Natija oynasidagi React — client to'plami. Biz React 19.3.0 ning client kodini ochib ko'rdik: u yerda cache shunchaki chaqiruvni o'tkazib yuboradi (return fn.apply(null, arguments)). Sinab ko'ring:
import { cache } from "react";
let calls = 0;
const getPost = cache((slug: string) => {
calls++;
console.log(`tana ishladi: ${slug}`);
return { slug, title: "Portfolio'ni Next.js'da qayta qurdim" };
});
getPost("portfolio-v2");
getPost("portfolio-v2");
console.log("chaqiruvlar:", calls);
export default function App() {
return <p>{getPost("portfolio-v2").title}</p>;
}Konsolda:
tana ishladi: portfolio-v2
tana ishladi: portfolio-v2
chaqiruvlar: 2
tana ishladi: portfolio-v2Ekranda:
Portfolio'ni Next.js'da qayta qurdimTana uch marta ishladi — eslab qolish yo'q. Bu xato emas: client'da "bitta so'rov" tushunchasi yo'q, foydalanuvchi bilan sahifa soatlab ochiq turadi. Serverda esa xuddi shu kod har so'rovda birinchi chaqiruvni bajaradi, qolganini birlashtiradi. Shuning uchun cache() ni client komponentda ishlatmang — u yerda useMemo va memoizatsiya usullari bor.
2.4 So'rov doirasi: o'quv modeli
Serverdagi xulqni oddiy JS bilan takrorlaymiz. Har so'rov — yangi Map (React buni o'zi qiladi, biz qo'lda):
let bodyRuns = 0;
function readPost(slug) {
bodyRuns++;
return `«${slug}» matni`;
}
// Har so'rovga yangi xotira — React cache() g'oyasi
function handleRequest(name, render) {
const memo = new Map();
const postniOl = (slug) => {
if (!memo.has(slug)) memo.set(slug, readPost(slug));
return memo.get(slug);
};
render(postniOl);
console.log(`${name}: tana jami ${bodyRuns} marta`);
}
const page = (postniOl) => {
postniOl("salom"); // generateMetadata
postniOl("salom"); // sahifa
postniOl("salom"); // muallif bloki
};
handleRequest("1-so'rov", page);
handleRequest("2-so'rov", page);Konsolda:
1-so'rov: tana jami 1 marta
2-so'rov: tana jami 2 martaBitta so'rov ichida uch chaqiruv — bitta o'qish. Ikkinchi so'rov o'z xotirasi bilan boshlandi va yana bir marta o'qidi. So'rovlararo saqlash — "use cache" ning ishi.
Tekshirib ko'ring:
postniOlnicache()siz, oddiy funksiya qilib qoldirsak, bitta sahifa ochilgandareadPostnecha marta ishlaydi?
Javob
Uch marta — generateMetadata, sahifa va muallif bloki uchun alohida. cache() bilan — bir marta.
3. Kanon o'lchovi: 4 dan 2 ga
3.1 Tajriba
Kanon postniOl va post() ichiga vaqtincha console.log hisoblagich qo'yib, next build qildi — cache() bilan va usiz (natijalar/tajriba/20-cache-dedup.txt):
## cache() bilan
1 [olchov] post() tanasi: portfolio-v2
1 [olchov] post() tanasi: server-components
1 [olchov] post() tanasi: vazifalar-testlari
2 [olchov] postniOl: portfolio-v2
2 [olchov] postniOl: server-components
2 [olchov] postniOl: vazifalar-testlari
## cache() SIZ
1 [olchov] post() tanasi: portfolio-v2
1 [olchov] post() tanasi: server-components
1 [olchov] post() tanasi: vazifalar-testlari
4 [olchov] postniOl: portfolio-v2
4 [olchov] postniOl: server-components
4 [olchov] postniOl: vazifalar-testlariChapdagi son — shu qator logda necha marta chiqqani.
- postniOl, cache() siz4 marta
- postniOl, cache() bilan2 marta
- post() tanasi (use cache)1 marta
Manba: IlmHamroh kanoni, portfolio v2 holat 20, next build, natijalar/tajriba/20-cache-dedup.txt, 2026-10-21
3.2 Raqamlarni o'qish
Nega 4? Cache Components'da har slug ikki marta prerender qilinadi (Next.js ichki tekshiruvi uchun). Har birida generateMetadata ham, sahifa ham postniOl ni chaqiradi: 2 × 2 = 4. cache() bitta render ichidagi ikkita chaqiruvni birlashtiradi: 4 → 2.
Endi uchinchi ustunga qarang: post() tanasi — haqiqiy fayl o'qish — har ikki holatda ham 1. Chunki post() ichida "use cache" bor (Cache Components I): u so'rovlararo kesh, birinchi chaqiruvdan keyin fayl qayta o'qilmaydi.
Halol xulosa: ma'lumot "use cache" ortida bo'lsa, cache() faqat o'ram chaqiruvlarini tejaydi. Fayl yoki baza baribir bir marta o'qiladi. cache() ning haqiqiy foydasi — keshlanmagan murojaatlarda: foydalanuvchiga xos baza so'rovi, joriy foydalanuvchini aniqlash, har so'rovda o'zgaradigan ma'lumot. Bular 26–28-qismlarda keladi (baza va auth). Kanon DAL'ni hozir qo'ydi — tuzilma tayyor bo'lsin.
3.3 fetch uchun bu o'zi bor
Serverda ma'lumot olish darsida aytilgan edi: bir render ichidagi bir xil fetch (manzil va sozlamalar bir xil, GET) Next.js'da avtomatik birlashtiriladi. Bu request memoization (so'rov ichidagi memoizatsiya) deyiladi. cache() — xuddi shu narsa, lekin fetch bo'lmagan funksiyalar uchun: fayl, baza, hisob-kitob.
Next.js hujjatidagi qoida: fetch — memoizatsiya o'zi; ORM yoki baza — React.cache bilan o'rang.
4. Data Access Layer
4.1 Muammo: ma'lumot hamma joyda
Kichik loyihada har sahifa ma'lumotni o'zi oladi: biri post() ni, biri loyihaniTop() ni, uchinchisi to'g'ridan faylni o'qiydi. Loyiha o'sganda savollar paydo bo'ladi:
- Bu ma'lumotni kim ko'ra oladi? Tekshiruv qaysi faylda?
- Sahifaga butun yozuv ketyaptimi yoki faqat kerakli maydonlar?
- Bu modul tasodifan brauzer to'plamiga tushib qolmaydimi?
Har sahifada alohida javob — har sahifada alohida xato imkoniyati. Next.js hujjati yangi loyihalar uchun boshqa yo'lni tavsiya qiladi.
4.2 Naqsh
Data Access Layer (DAL) — ma'lumotga murojaat qiladigan yagona server modul. Hujjat uchta talab qo'yadi:
- Faqat serverda ishlaydi.
- Ruxsat (avtorizatsiya) tekshiruvini o'zi qiladi.
- Xavfsiz, minimal DTO qaytaradi.
DTO (Data Transfer Object — ma'lumot uzatish obyekti) — sahifaga beriladigan, faqat kerakli va ochiq maydonlardan iborat obyekt. Bazadagi yozuvda parol xeshi, telefon raqami, ichki izohlar bo'lishi mumkin — DTO'da faqat sahifa ko'rsatadigan narsa.
flowchart LR
P1["loyihalar/[slug]/page.tsx"] --> D["dal.ts<br/>server-only, cache(), DTO"]
P2["blog/[slug]/page.tsx"] --> D
M["generateMetadata"] --> D
D --> B["blog.ts: fayllar"]
D --> L["loyihalar.ts: ro'yxat"]
D -. "28-qism" .-> A["auth tekshiruvi"]Diagrammada sahifalar va metadata faqat dal.ts ga qaraydi. Ma'lumot manbalari (fayl, ro'yxat, keyin baza) uning orqasida yashiringan.
4.3 Kanon dal.ts
import "server-only";
import { cache } from "react";
import { post } from "./blog";
import { loyihaniTop } from "./loyihalar";
// Data Access Layer (N-20): sahifalar ma'lumotni faqat shu
// yerdan oladi.
// - `server-only`: client bundle'ga tushmaydi;
// - React `cache()`: BITTA so'rov (render) ichida
// generateMetadata va sahifa bir xil chaqiruvni bo'lishadi;
// - DTO: sahifaga faqat kerakli maydonlar (keyin auth
// qo'shilsa — tekshiruv ham shu yerga, 28-qism).
export const postniOl = cache(async (slug: string) => post(slug));
export const loyihaniOl = cache(async (slug: string) => {
const l = loyihaniTop(slug);
if (!l) return null;
const { repo, ...ochiq } = l; // repo — ichki maydon
return { ...ochiq, repoUrl: `https://github.com/${repo}` };
});Kanon izohlari telefonga sig'ishi uchun bo'lindi; repo qatoridagi izoh qisqartirildi (aslida: "repo — ichki maydon (statistika uchun), sahifaga kerak emas").
| Qator | Ma'nosi |
|---|---|
import "server-only" |
Client komponent import qilsa — build xatosi |
cache(async (slug) => post(slug)) |
Bitta render ichida bir marta |
const { repo, ...ochiq } = l |
Rest bilan repo ni ajratib tashlash |
repoUrl: … |
Sahifaga tayyor havola — ichki format emas |
repo — "octocat/vazifalar" ko'rinishidagi ichki qiymat. Sahifa unga muhtoj emas, faqat havola kerak. Bugun bu xavfsizlik masalasi emas (repo nomi ochiq), lekin odat muhim: DAL nima chiqishini hal qiladi, sahifa emas.
4.4 Natija oynasida: DTO
DTO — oddiy funksiya, uni alohida sinash oson:
type Project = {
slug: string;
nomi: string;
repo: string;
ichkiIzoh: string;
};
type ProjectDto = Omit<Project, "repo" | "ichkiIzoh"> & {
repoUrl: string;
};
function toDto(p: Project): ProjectDto {
const { repo, ichkiIzoh, ...open } = p;
return { ...open, repoUrl: `https://github.com/${repo}` };
}
const project: Project = {
slug: "vazifalar",
nomi: "Vazifalar",
repo: "octocat/vazifalar",
ichkiIzoh: "mijoz bilan narx kelishilmagan",
};
console.log(toDto(project));Konsolda:
{
slug: 'vazifalar',
nomi: 'Vazifalar',
repoUrl: 'https://github.com/octocat/vazifalar'
}ichkiIzoh sahifaga umuman yetib bormadi. Omit (utility turlar) qaytish turini ham shunga moslaydi: sahifa kodida dto.ichkiIzoh deb yozsangiz — TypeScript xatosi. Bu muhim, chunki Server Component client komponentga prop bergan har bir maydon RSC payload orqali brauzerga ketadi (Server Components) — "faqat sahifada ishlataman" degan maydon ham.
4.5 server-only — qo'riqchi
import "server-only" — kichik paket, uning yagona vazifasi: fayl client komponent daraxtiga import qilinsa, build'ni to'xtatish. Kanon buni tajribada ko'rgan (Server va Client kompozitsiyasi, xom natijalar/tajriba/11-server-only-xato.txt):
Error: You're importing a module that depends on "server-only". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.Xabarning ikkinchi yarmi chalg'ituvchi: kanonda Pages Router yo'q edi. Asosiysi — build to'xtadi va sir modul brauzerga ketmadi.
4.6 Ruxsat tekshiruvi ma'lumot yonida
Portfolio'da hamma narsa ochiq — tekshiradigan narsa yo'q. Lekin 28-qismda login paydo bo'lganda tekshiruv DAL ichiga qo'yiladi, sahifaga emas. Sxema (hozir ishlamaydi — auth hali yo'q):
// dal.ts — 28-qismdan keyin (sxema)
export const vazifalarniOl = cache(async () => {
const foydalanuvchi = await joriyFoydalanuvchi(); // cache() bilan
if (!foydalanuvchi) return null; // yoki redirect("/kirish")
const royxat = await db.vazifa.findMany({
where: { egasiId: foydalanuvchi.id }, // faqat o'ziniki
});
return royxat.map((v) => ({ id: v.id, matn: v.matn }));
});Nega sahifada emas? Layout yoki sahifadagi tekshiruvni chetlab o'tish mumkin: masalan, ma'lumot boshqa yo'l bilan — Route Handler, Server Action yoki boshqa sahifa orqali olinsa. Tekshiruv ma'lumotning o'zida bo'lsa, qayerdan chaqirilmasin, u ishlaydi. Next.js hujjati ham layout'da auth tekshirishdan ogohlantiradi: layout navigatsiyada qayta chizilmaydi (Layout va template).
4.7 Hujjatdagi qo'shimcha himoya: taint
React'da tajribaviy API bor — experimental_taintObjectReference va experimental_taintUniqueValue. Ular obyektni yoki qiymatni (masalan token) "brauzerga o'tmasin" deb belgilaydi: tasodifan client komponentga prop qilib berilsa — xato. Next.js'da experimental.taint sozlamasi bilan yoqiladi. Nomidagi experimental — API hali barqaror emas. Kanon uni ishlatmadi: DTO yetarli. Biladigan bo'lib qo'ying — katta loyihalarda uchraydi.
5. generateMetadata va DAL
Kanon DAL bilan birga loyiha va post sahifalariga generateMetadata qo'shdi — har sahifa o'z sarlavhasini oladi:
// app/(sayt)/blog/[slug]/page.tsx
import type { Metadata } from "next";
import { postniOl } from "@/malumot/dal";
export async function generateMetadata({
params,
}: PageProps<"/blog/[slug]">): Promise<Metadata> {
const p = await postniOl((await params).slug);
return p
? { title: `${p.sarlavha} — Aziz Karimov`, description: p.tavsif }
: {};
}
export default async function PostSahifasi({
params,
}: PageProps<"/blog/[slug]">) {
const p = await postniOl((await params).slug);
if (!p) notFound();
// …
}Ikkalasi postniOl ni chaqiradi — cache() tufayli bir render ichida bitta chaqiruv. generateMetadata va Metadata turi — Metadata API darsida to'liq; bugun faqat DAL'dan foydalanuvchi sifatida.
6. cache() tuzoqlari
| Tuzoq | Nima bo'ladi | Davosi |
|---|---|---|
cache() ni komponent ichida chaqirish |
Har render yangi kesh — hech narsa birlashmaydi | Modul darajasida bir marta: export const x = cache(…) |
| Obyekt argument | Har chaqiruv yangi obyekt — boshqa kalit | Satr/son argument |
| Client komponentda | Eslamaydi (natija oynasidagidek) | Server kodida ishlating |
"use cache" ichiga cache() orqali qiymat uzatish |
Ko'rinmaydi — alohida doira (hujjat: "React.cache isolation") | Argument sifatida bering |
| Xato tashlagan chaqiruv | Xato ham eslanadi (shu so'rov ichida) | Xatoni ichkarida ushlang yoki qabul qiling |
7. Portfolio qadami: DAL va commit
7.1 Fayllar
| Fayl | O'zgarish |
|---|---|
src/malumot/dal.ts |
Yangi: server-only, postniOl, loyihaniOl (DTO: repo → repoUrl) |
(sayt)/blog/[slug]/page.tsx |
post() o'rniga postniOl(); yangi generateMetadata |
(sayt)/loyihalar/[slug]/page.tsx |
loyihaniTop() o'rniga loyihaniOl(); generateMetadata; havola loyiha.repoUrl |
Loyiha sahifasidagi o'zgarish:
- <a href={`https://github.com/${loyiha.repo}`}>GitHub'dagi kod</a>
+ <a href={loyiha.repoUrl}>GitHub'dagi kod</a>Ro'yxat sahifalari (/blog, /loyihalar) hozircha postlar() va LOYIHALAR ni to'g'ridan ishlatadi — kanon DAL'ni bitta yozuvli sahifalardan boshladi.
7.2 Tekshiruv va commit
npm run build — jadval o'zgarmadi (○ sahifalar, blog 30d 1y). Brauzerda: post sahifasining tabida endi post sarlavhasi. Kanon o'lchovi: JS o'zgarmadi, axe 0, hydration 0.
git add -A
git commitCommit (kanon): DAL: malumot/dal.ts (server-only, cache(), DTO); loyiha va post sahifalariga generateMetadata.
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| Bitta sahifada bir xil so'rov bir necha marta | Baza/fayl funksiyasi cache() siz |
cache() bilan o'rang |
cache() bor, lekin baribir ko'p chaqiruv |
Obyekt argument yoki komponent ichida yaratilgan | Oddiy argument, modul darajasi |
Client komponentda cache() "ishlamaydi" |
Client'da u o'tkazib yuboradi | Server kodiga ko'chiring |
…depends on "server-only"… build xatosi |
DAL client faylga import qilingan | Ma'lumotni Server Component'da oling, prop bilan bering |
| Brauzerga keraksiz maydonlar ketdi | Butun yozuv prop qilib berilgan | DTO |
| Ruxsat tekshiruvini chetlab o'tishdi | Tekshiruv faqat sahifa yoki layout'da | Tekshiruvni DAL ichiga |
cache() va "use cache" chalkashdi |
Biri so'rov ichida, biri so'rovlararo | «cache() va "use cache"» jadvali |
9. Mashqlar
Mashqlar kurs/mashqlar/23/20-dal/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.
1-mashq (oson): qaysi biri?
- Joriy foydalanuvchini bitta so'rov ichida 5 ta komponent so'raydi:
- Kurs ro'yxati hamma uchun bir xil, kuniga bir o'zgaradi:
- Foydalanuvchining savatchasi (cookie bo'yicha), bitta sahifada 3 joyda:
- Bir xil
fetchURL bitta render'da 2 marta: hech narsa — Next.js o'zi qiladi
Yechim
- cache() — foydalanuvchiga xos, faqat shu so'rov ichida.
- use cache — hamma uchun bir xil, so'rovlararo saqlanadi.
- cache() — savatcha shaxsiy;
"use cache"ichidacookies()taqiqlangan. - memoizatsiya — bir xil
fetchlar avtomatik birlashtiriladi.
2-mashq (o'rta): foydalanuvchi DTO'si
Bazadagi foydalanuvchi: { id, ism, email, telefon, parolXeshi, rol }. userDto(user, viewer) funksiyasini yozing: hamma ko'radi — id, ism; email — faqat o'zi yoki admin ko'radi (aks holda null); telefon — faqat o'zi; parolXeshi — hech qachon. Uchta viewer bilan sinang: o'zi, admin, begona.
Yechim
function userDto(user, viewer) {
const self = viewer.id === user.id;
const admin = viewer.rol === "admin";
return {
id: user.id,
ism: user.ism,
email: self || admin ? user.email : null,
telefon: self ? user.telefon : null,
};
}
const user = {
id: 7,
ism: "Malika",
email: "malika@example.com",
telefon: "+998 90 000 00 00",
parolXeshi: "$argon2id$…",
rol: "talaba",
};
console.log(userDto(user, { id: 7, rol: "talaba" }));
console.log(userDto(user, { id: 1, rol: "admin" }));
console.log(userDto(user, { id: 9, rol: "talaba" }));Konsolda:
{
id: 7,
ism: 'Malika',
email: 'malika@example.com',
telefon: '+998 90 000 00 00'
}
{ id: 7, ism: 'Malika', email: 'malika@example.com', telefon: null }
{ id: 7, ism: 'Malika', email: null, telefon: null }DTO'ni "nima olib tashlansin" (rest bilan) emas, "nima qo'shilsin" deb qurish xavfsizroq: bazaga yangi maxfiy maydon qo'shilsa, u avtomatik DTO'ga tushib qolmaydi. Kanondagi { repo, ...ochiq } usuli qisqa, lekin shu xavfni o'zida saqlaydi — ochiq ma'lumotli kichik ro'yxat uchun qabul qilinadi.
3-mashq (qiyin): so'rov doirasidagi memo
«So'rov doirasi» modelini universal qiling: createRequestCache() — ichida Map bo'lgan obyekt qaytaradi va wrap(fn) metodi bor: wrap(fn) qaytargan funksiya birinchi argument bo'yicha natijani eslaydi. Ikki xil funksiya (readPost, readProject) bitta so'rovda bir xil argument bilan chaqirilsa, natijalar aralashmasligi kerak (har wrap — o'z Map i). Ikki so'rovni simulyatsiya qiling va har funksiya tanasi necha marta ishlaganini chiqaring.
Yechim
const runs = { post: 0, project: 0 };
function createRequestCache() {
return {
wrap(fn) {
const memo = new Map();
return (key) => {
if (!memo.has(key)) memo.set(key, fn(key));
return memo.get(key);
};
},
};
}
function readPost(slug) {
runs.post++;
return `post:${slug}`;
}
function readProject(slug) {
runs.project++;
return `loyiha:${slug}`;
}
for (const name of ["1-so'rov", "2-so'rov"]) {
const req = createRequestCache();
const getPost = req.wrap(readPost);
const getProject = req.wrap(readProject);
getPost("vazifalar");
getPost("vazifalar");
console.log(getProject("vazifalar"), getPost("vazifalar"));
console.log(name, runs);
}Konsolda:
loyiha:vazifalar post:vazifalar
1-so'rov { post: 1, project: 1 }
loyiha:vazifalar post:vazifalar
2-so'rov { post: 2, project: 2 }Har wrap o'z Map iga ega — "vazifalar" kaliti ikki funksiyada aralashmadi. React cache() ham har o'ralgan funksiya uchun alohida xotira tutadi va har so'rov boshida uni yangilaydi.
4-mashq: Portfolio qadami
src/malumot/dal.ts ni yarating, loyiha va post sahifalarini DAL'ga o'tkazing, ikkalasiga generateMetadata qo'shing. npm run build toza bo'lsin. Tajriba: dal.ts ni biror client komponentga import qilib ko'ring — server-only xatosini ko'ring va qaytaring. Keyin commit.
Yechim
Namuna — «Kanon dal.ts» va «generateMetadata va DAL» bo'limlaridagi kod. Tekshirish: /blog/portfolio-v2 tabida «Portfolio'ni Next.js'da qayta qurdim — Aziz Karimov». Loyiha sahifasidagi «GitHub'dagi kod» havolasi https://github.com/… ga olib boradi. Commit xabari — kanondagi.
10. Real ishda
- DAL — Next.js jamoasining yangi loyihalar uchun rasmiy tavsiyasi. Katta jamoalarda
data/yokilib/dal/papkasi va "sahifa bazaga to'g'ridan murojaat qilmaydi" qoidasi. - DTO — backend'da ham asosiy naqsh (NestJS'da 25+ qismlar): API javobida parol xeshi yoki ichki ID chiqib ketishi — real xavfsizlik hodisalarining tez-tez sababi.
cache()— auth bilan birga eng ko'p ishlatiladi:getCurrentUser()bir sahifada 10 joyda chaqiriladi, sessiya esa bir marta tekshiriladi.- Intervyuda: "
React.cacheva Next.js keshi farqi?", "Server Component'dan client'ga nima ketadi?".
Xulosa
cache()bitta so'rov ichida bir xil chaqiruvlarni birlashtiradi;"use cache"— so'rovlararo kesh.- Kanon:
cache()chaqiruvlarni 4 → 2 ga tushirdi; fayl o'qish"use cache"tufayli baribir 1 marta. cache()ning asosiy foydasi — keshlanmagan, foydalanuvchiga xos so'rovlarda; client'da u hech narsani eslamaydi.- DAL — yagona server modul:
server-only,cache(), DTO va ruxsat tekshiruvi ma'lumot yonida. - DTO sahifaga faqat kerakli maydonlarni beradi — client'ga prop bo'lgan har maydon brauzerga ketadi.
Keyingi dars: Server Actions I: "use server" va formalar — «Aloqa» formasi serverga to'g'ridan yozadi, hatto JavaScript'siz ham.
Manbalar
- React hujjati —
cache: https://react.dev/reference/react/cache (2026-10-21 da o'qildi) - Next.js hujjati — Data Security 16.4-bob: https://nextjs.org/docs/app/guides/data-security
- Next.js hujjati — Fetching Data, Reusing data with React.cache: https://nextjs.org/docs/app/getting-started/fetching-data
- Kanon o'lchovlari:
portfoliov2, holat 20 (natijalar/tajriba/20-cache-dedup.txt,11-server-only-xato.txt); clientcachexulqi — React 19.3.0react.development.jsva natija oynasi.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!