Розумеўце дырэктыву “use cache” і функцыі паўтарной пераверкі на адзецоўскай аснове у Next.js 16.
Дакледзіце, як працюе дырэктыва “use cache” у Next.js 16, яе функцыі паўтарной пераверкі даных, а таксама як застосоўваць кэшаванне, ўрахоўваючы аблікантаў, у багатоабліканаўскіх дапытках.
У Next.js кэшаванне традыцыйна вважалася чымось на кшталт „чорнай скрыванкі“ — сумятыцею з настройкамі на рэвэлі файлаў, параметрамі, якія перадаюцца функцыі fetch, і стандартнымі настройкамі фрэймворку, якія дастаткова зменяліся между версіямі, так што нават апытныя разработчыкі заставалі документацыю адкрытай, ўбачлівасці. Дырэктыва "use cache", адкрытая ў Next.js 16 як частка шырэйшай моделі Cache Components, змінюе гэтая ситуацыю, адколі дозволяе явна задаць поведзенне кэшавання на рэвэлі компонента або функцыі, замест таго каб яно інхерітавалася неявна з стандартных настройкаў, якія трэба памяцать.
Нижчэй прыводзіцца разбор таго, што на самай працэ прадзейснюе гэтая дырэктыва, і ситуацый, калі ёе выкарыстоўванне мае сэнс.
Што на самай працэ прадзейснюе дырэктыва
Размішчэнне "use cache" усередине функцыі або компонента паведамляе Next.js кэшаваць тое, што вяртае гэта функцыя. Канцэптуальна яна выполняе роль, падобную "use client", але замест таго, каб пазначыць межу кліентскай часткі, яна пазначае межу кэшавання:
async function getDashboardStats(tenantId: string) {
"use cache";
const stats = await db.query.stats.findMany({ where: { tenantId } });
return stats;
}
Результат выконання функцыі кэшуецца і прызначаецца ключам на аднойчынку на адварот з пасункамі, якія былі переданы, пасля чаго воспользваецца ў наступных запытках, пакуль што-небудзь не знецініць яго. Гэта справжня адміністрацыя ад старэйшага падходу кэшавання окремага запытку fetch або цэлага сегмента маршрута: тепер можна кэшаваць на будзь-якай гранулярнасці, якая падходзіць вашым данным, аж да адной конкрэтнай функцыі.
Тры дапаможныя функцыі
Паралельна з гэтым дырективам, Cache Components прыводзіць невялікі набор API для цэльвым управління кэшаванымі даннымі, замест таго, каб проста чакаць заканчэння таймера:
revalidateTag(tag)— адзьявляе ўсі элементы кэшу, якія асоціююцца з заданым тэгам. Гэта стаўкаеся калі адна змяненае значэнне паўтарае даны, на якія спакоююцца калькольванні каля кількох разных функцый кэшу.updateTag(tag)— болей спецыфічная версія таго ж прынцыпу, якая метаюцца ў адзьявленні конкрэтных элементаў кэшу, якія звязаны з адним тэгам, а не з усім, што належыць да яго.refresh()— адзьявляе даны кэшу, якія стосуюцца тэкучага запиту.
Ўжо ўсё тое, што робіць весь система эфектываю: прыкрепіце значаменны тэг да кожнай функцыі, якая зберагаецца у кэшы — на прыклад tenant-stats або invoice-list — і кожны раз, калі вырабляецца змяненне, якое паўтараецца на тых данных, вызывайце revalidateTag з адпаведным тэгам, узамен таго каб прабаваць выбраць період заканчэння часовага кэшавання, які будзе занадта короткі (чым супершчытваецца мета кэшавання) або занадта дзьвігуты (чым паслужаюць старыя данні).
async function getInvoices(tenantId: string) {
"use cache";
cacheTag(`invoices-${tenantId}`);
return db.query.invoices.findMany({ where: { tenantId } });
}
// After creating an invoice:
async function createInvoice(data: InvoiceInput) {
await db.insert(invoices).values(data);
revalidateTag(`invoices-${data.tenantId}`);
}
Гэтае соўпаданне — прыкреплення тэга пад час чытання, пераверыцеўка пад час збірання — насправдзе ёсць вся ідея ў скрацанама форме. Практычна всё інша, што вы будетэ делаць з гэтай системай, ёсць варіяцыяю таго ж паўтарэння.
Пашырэныя моменты плутання
Самая часта памылка, у якой страждаюць команды, — гадка, што "use cache" ўсё тое ж, што і опцыя next: { revalidate } у функцыі fetch(). Насам працэй яны рашаюць разныя, хоць і супакойнае, проблемы. Опцыя на рэвэлі fetch() керуе адзінам сетевым запитам. "use cache" кэшуе рэзультат цэлай функцыі або компонента, якая внутршняя часткай можа выконваць горазд за адно — запытваць базу дадзэння, выконваць якіясь вычысленні, а можа і сама вызываць fetch. Якщо вам патрэбна толькі кэшаванне аднаго зовнішняга запыту API, то варэнне кэшавання на рэвэлі fetch() зазвычай ёсць простейшым выборам. "use cache" становіцца корыстным тады, калі вы хочаце кэшаваць цэлы рэзультат вычыслень, а не толькі адзін запыт, який яго стварае.
Другая частая памяць — це ўсуненне крока прызначэння тагоў цалкам, пасля чаго з’являецца плутанне, калі мутацыя не можа вычыстыць захаваныя даны, якія ўжо павінны быць вычыстыты. Без прызначанага таго єдыны механізм анулювання — це час, што падмаўляе вялічзину прычын, за якімі спачатку была выбрана гэта модель — вы прыймаеце дадатковую складнась явнага кэшавання, не маючы явнаг контролю над анулюванням.
Тагі, якія врачаюць інформацыю пра арендніка, для багатоарендных дапрацоўак
Якщо вы працюеце над чым-небудзь, што падтрымлівае калькольнікаў, існуе деталь, яку варта адразу згадаць: тагі павінны кодаваць інформацыю пра калькольніка, а не толькі тип дадзэйна, які зберагаецца у кешы. Універсальны таг, такі як invoices, які викорыстоўваецца для всіх калькольнікаў, означае, што анулюванне дадзэйна одного калькольніка анулюе яго і для всіх — што можа прызвесці аб проблемамі з правильнасцю (адзін калькольнік бачыць застарэлыя результаты, таму што мутацыя іншага калькольніка спрычыніла спяльную перапрацоўку), аб проблемамі з выдаткамі (каш чыстаецца значна частае, чым трэба). Такі формат, як invoices-${tenantId}, які викорыстоўваецца ў прыкладзе вышэй, не ёсць праграмнай прыяжнасцю — гэта тое, што адзначае эфектыўную стратэгію анулювання ад неэфектыўной.
Чаму важна правільна наладзіць гэта з самага пачатку
Слою кэшавання з незначным дзеяннем рэдкасць выклікае явныя проблемы. У замест на гэта ён частае выражаецца у нечыткіх запитах на падтрымку, такіх як "чаму на гэтым панелі керавання яшчэ апісваюцца цифры з минулага тыдня" — багі, якія дасправда працою стварае праблемы з аднаведэнням, таму што некоректны маршрут анулювання часта знаходзіцца там, куды ніхто не прыкладваў рукі месяцямі. Выбіранне адпаведнай стратэгіі пазначэння з самага пачатку і ўніверсальнае яе застосаванне да кожной функцыі, якая знаходзится у кэшы, ў кодбазе, являецца аднам з тых выбораў інфраструктуры, якія даскладнае выкарыстоўваць правільна з самага пачатку, але ўсё дорожэ выправляць пазней.
Дзеяныя наборы для стварэння панелей керування будуюць свой шар дадзэйна адносова да гэтых прынцыпаў. Напрыклад, шаблон на кшталт шаблона панелі керування Ovyqen для проектаў Next.js і SaaS выкарыстоўвае падход «дадаць таг при чытанні, перапрацаваць дадзеныя при збераганні» ў всім, спачатку включаючы ідэнтыфікаторы корыстувачаў у кожны таг, а не дадаючы іх пазней пасля проблем з кэшаванням між корыстувачамі. Якщо вы рассматрываеце шаблоны панелей керування, а невярна працэс кэшавання є тым аспектам вашага чыннага прыемлівання, якому ніхто не давае паверы, то гэта ўсуперш цяплы адказ на пачатак работы з фундаментам, які вже правільна рашае гэтыя проблемы.
Часта задаваемыя запитанні
Чы гэтыя вызовы fetch() трэба пераводзіць на "use cache"? Не павінна — гэтыя два механізма часткова перакрываюцься, але не ўзаемна заменяюцься. Кэшаванне на рэвэлі fetch() заступаецца для простых сцэнарыёў з адним запитам. Варта выкарыстоваць "use cache", калі трэба кэшаваць расчыслены результат або выходную інфармацыю цэлага компонента.
Чы "use cache" дастаткова вырашаны для практычнага вжывання ў дашбордах? Ставіцеся да яго так сама, як і да будзь-яго сапраўдна моладога механізма кэшавання — рэгулярна тэставаць шляхі анулювання кэша, у чыяму разе ўсё болей актуальна проблема кэшаўання дадзеных для кальколяроў, перш чым паспеліваць на яго для будзь-чага, што праглядаецца кліентамі і дзе важліва актуальнасць інфармацыі.
Што будзе, як функцыя з кэшу застанется без атрыбутаў? Кэшаванне все равно будзе адбывацца, але вы пазбярэце можлівасць намерна анулюваць яго у зв’язку з конкрэтным запускам. Вы будете завісіць выключна ад тэрміну заканчыць кэшавання, які рэдкая раз працюе так, як вы насправды хочаце.
Явна настройка кэшавання выклікае больш пачатковых зусиль, чым проста доверэнне стандартным настройкам фреймворку. Але для данных панелі керування, дзе показ старых данных мае рэальныя наследкі, гэты дадзены зусиллі практычна завжды є правильным выборам.
Спадні матэрыялы
- Розумеўце компаненты кэшу і частковае прадзержванне ў Next.js 16.3 — Паспяшаея, як функцыя Instant Navigations у Next.js 16.3 выкарыстоўвае спяльныя шэлі маршрутаў і явныя рашэння пра стрімінг, каб дапамогчы серверным аплікацыям працаваць мгновенна.