Пошук уроків, статей та іншого контенту
З’ясуєте, як Next.js автоматично дедуплікує однакові запити під час рендерингу дерева компонентів.
Request Memoization — це автоматичне дедуплікування однакових fetch-запитів під час одного рендерингу дерева компонентів.
Уявімо, що двом серверним компонентам потрібні дані одного й того самого ресурсу:
Page
├── PostTitle
└── PostDetailsОбидва компоненти викликають:
fetch("https://example.com/posts/1")Next.js виконає фактичний HTTP-запит лише один раз, а результат використає повторно для обох компонентів.
Це допомагає:
не надсилати однаковий запит кілька разів;
уникати зайвого навантаження на API;
передавати дані різним компонентам без підняття їх у спільний батьківський компонент.
Next.js автоматично розширює стандартний fetch на сервері. Якщо під час одного рендерингу зустрічаються однакові запити, Next.js повертає вже отриманий результат замість повторного звернення до сервера.
Запити вважаються однаковими, коли збігаються:
URL;
метод;
параметри запиту;
заголовки;
інші параметри fetch.
Найчастіше це стосується запитів із методом GET, оскільки саме їх зазвичай використовують для отримання даних.
Важливо: мемоізується саме виклик fetch, а не довільна функція навколо нього.
Створімо сторінку, на якій два серверні компоненти запитують один і той самий пост.
const POST_URL = "https://jsonplaceholder.typicode.com/posts/1";
async function PostTitle() {
const response = await fetch(POST_URL);
if (!response.ok) {
throw new Error("Не вдалося завантажити пост");
}
const post = await response.json();
return <h1>{post.title}</h1>;
}
async function PostDetails() {
const response = await fetch(POST_URL);
if (!response.ok) {
throw new Error("Не вдалося завантажити пост");
}
const post = await response.json();
return <p>{post.body}</p>;
}
export default function Page() {
return (
<main>
<PostTitle />
<PostDetails />
</main>
);
}Цей файл можна розмістити як app/page.js у проєкті Next.js з App Router.
На перший погляд, у коді є два виклики:
fetch(POST_URL);Проте під час одного рендерингу Next.js дедуплікує їх, оскільки URL і параметри запитів однакові.
У прикладі кожен компонент окремо викликає fetch. Так Next.js може розпізнати однакові запити.
Можна також винести запит у функцію:
const POST_URL = "https://jsonplaceholder.typicode.com/posts/1";
async function getPost() {
const response = await fetch(POST_URL);
if (!response.ok) {
throw new Error("Не вдалося завантажити пост");
}
return response.json();
}
async function PostTitle() {
const post = await getPost();
return <h1>{post.title}</h1>;
}
async function PostDetails() {
const post = await getPost();
return <p>{post.body}</p>;
}
export default function Page() {
return (
<main>
<PostTitle />
<PostDetails />
</main>
);
}У цьому випадку функція getPost буде викликана двічі. Але самі однакові виклики fetch усередині неї будуть дедупліковані Next.js.
Отже, потрібно розрізняти:
функція getPost викликається двічі;
HTTP-запит fetch(POST_URL) виконується один раз під час цього рендерингу.
Request Memoization працює в межах одного процесу рендерингу React-дерева.
Вона не означає, що результат автоматично зберігатиметься назавжди або буде використаний під час усіх майбутніх запитів до сторінки.
Тобто:
сервер починає рендерити сторінку;
кілька компонентів викликають однаковий fetch;
Next.js виконує один запит;
компоненти отримують спільний результат;
після завершення рендерингу дія цієї мемоізації завершується.
Request Memoization потрібно відрізняти від кешування даних у Next.js:
Request Memoization прибирає дублікати під час одного рендерингу;
Data Cache може зберігати результат запиту для повторного використання пізніше.
Це різні механізми, хоча обидва пов’язані з fetch.
Якщо параметри відрізняються, Next.js розглядатиме запити як різні:
fetch("https://api.example.com/users/1");
fetch("https://api.example.com/users/2");Так само різними будуть запити з різними заголовками:
fetch("https://api.example.com/profile", {
headers: {
Authorization: "Bearer token-a",
},
});
fetch("https://api.example.com/profile", {
headers: {
Authorization: "Bearer token-b",
},
});У такому випадку потрібні два окремі HTTP-запити.
Request Memoization призначена переважно для повторюваних запитів на отримання даних. Запити з методом POST автоматично не дедуплікуються так само, як стандартні GET-запити.
fetch("https://api.example.com/orders", {
method: "POST",
body: JSON.stringify({
productId: 10,
}),
});POST зазвичай змінює дані на сервері, тому автоматичне об’єднання таких запитів могло б бути небезпечним.
Щоб однакові запити могли бути дедупліковані, використовуйте однакові параметри:
const options = {
headers: {
Accept: "application/json",
},
};
fetch("https://api.example.com/posts/1", options);
fetch("https://api.example.com/posts/1", options);Не змінюйте без потреби URL або параметри в різних компонентах:
fetch("https://api.example.com/posts/1", {
headers: {
Accept: "application/json",
},
});
fetch("https://api.example.com/posts/1", {
headers: {
"Content-Type": "application/json",
},
});Ці запити можуть не вважатися однаковими, оскільки їхні параметри відрізняються.
Request Memoization застосовується до серверного рендерингу компонентів Next.js.
Серверний компонент може напряму виконувати:
const response = await fetch("https://api.example.com/data");Клієнтський компонент із директивою "use client" працює в іншому середовищі. Для цієї теми важливо запам’ятати: автоматична дедуплікація однакових запитів стосується fetch, який виконується під час серверного рендерингу дерева компонентів.
Request Memoization не гарантує, що дані залишаться доступними для всіх наступних запитів. Вона усуває дублікати в межах конкретного рендерингу.
Навіть невелика різниця в URL або опціях може зробити запити різними:
fetch("https://api.example.com/items?page=1");
fetch("https://api.example.com/items?page=2");Це два різні запити, і саме так має бути.
Next.js автоматично працює з fetch, а не з будь-якими функціями:
async function getData() {
console.log("Виклик функції");
return fetch("https://api.example.com/data");
}Виклик getData() може відбутися кілька разів. Дедуплікація стосується однакового запиту fetch усередині функції.
POST для отримання даних і очікування автоматичної дедуплікаціїPOST не слід розглядати як звичайний мемоізований запит для отримання даних. Для безпечної роботи з такими запитами потрібна окрема логіка.
Request Memoization автоматично прибирає дублікати однакових fetch-запитів.
Механізм працює під час одного рендерингу дерева серверних компонентів.
Для дедуплікації URL і параметри запитів мають збігатися.
Два компоненти можуть запитувати одні й ті самі дані, але фактичний HTTP-запит буде виконано один раз.
Мемоізується виклик fetch, а не функція-обгортка навколо нього.
Request Memoization не слід плутати з постійним Data Cache.
Запити з різними параметрами та POST-запити не потрібно очікувати як автоматично дедупліковані.