Доки по разработке
This project is maintained by teniryte
Модуль 18-lazy-loading демонстрирует несколько важных техник:
next/dynamic),fuse.js),prefetch ссылок.next/dynamicФункция dynamic из next/dynamic позволяет:
ssr: false),loading‑компонент.Простой пример:
import dynamic from 'next/dynamic';
const HeavyComponent = dynamic(() => import('./HeavyComponent'));
export default function Page() {
return (
<div>
<h1>Lazy Loading</h1>
<HeavyComponent />
</div>
);
}
Принципы:
dynamic, когда компонент:
В примере из вашего проекта:
HeavyComponent импортируется с опцией ssr: false;Паттерн:
import dynamic from 'next/dynamic';
const HeavyBrowserOnlyComponent = dynamic(
() => import('./HeavyBrowserOnlyComponent'),
{
loading: () => <p>Загрузка...</p>,
ssr: false, // отключаем SSR
},
);
Когда так делать:
window, document, localStorage, navigator и т.п.Файл 01-client-components.tsx показывает:
Паттерн:
// 'use client' обязательно, т.к. компонент использует состояние
'use client';
import dynamic from 'next/dynamic';
import { useState } from 'react';
const ComponentA = dynamic(() => import('./components/A')); // отдельный бандл
const ComponentB = dynamic(() => import('./components/B')); // подгружается по условию
const ComponentC = dynamic(() => import('./components/C'), { ssr: false });
export default function ClientComponentExample() {
const [showMore, setShowMore] = useState(false);
return (
<div>
{/* Загружается сразу, но в отдельном клиентском бандле */}
<ComponentA />
{/* Загружается только когда showMore === true */}
{showMore && <ComponentB />}
<button onClick={() => setShowMore((prev) => !prev)}>Toggle</button>
{/* Рендерится только на клиенте, без SSR */}
<ComponentC />
</div>
);
}
Принципы:
fuse.js)В 02-external-libraries.tsx ваш код делает следующее:
names,fuse.js,Fuse,Паттерн:
// 'use client'
import { useState } from 'react';
const names = ['Tim', 'Joe', 'Bel', 'Lee'];
export default function SearchWithFuse() {
const [results, setResults] = useState<any[]>([]);
const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const { value } = e.currentTarget;
// Динамический импорт только при необходимости
const Fuse = (await import('fuse.js')).default;
const fuse = new Fuse(names);
setResults(fuse.search(value));
};
return (
<div>
<input type="text" placeholder="Search" onChange={handleChange} />
<pre>Results: {JSON.stringify(results, null, 2)}</pre>
</div>
);
}
Принципы:
import Fuse from 'fuse.js'; // грузится сразу
делайте:
const Fuse = (await import('fuse.js')).default; // грузится только по событию
Файл 03-custom-loading.tsx демонстрирует:
loading‑компонент в dynamic,Паттерн:
// 'use client'
import dynamic from 'next/dynamic';
const WithCustomLoading = dynamic(
() => import('./components/WithCustomLoading'),
{
loading: () => <p>Loading...</p>, // показывается, пока идёт загрузка
},
);
export default function Page() {
return (
<div>
<WithCustomLoading />
</div>
);
}
Принципы:
loading должен быть лёгким компонентом, без тяжёлой логики.Файл 04-named-exports.tsx показывает пример:
dynamic.Паттерн:
import dynamic from 'next/dynamic';
// Предположим, что файл ../components/hello.ts экспортирует именованный компонент Hello
const ClientComponent = dynamic(() =>
import('../components/hello').then((mod) => mod.Hello),
);
Принципы:
dynamic должен указать, какой именно экспорт использовать..then((mod) => mod.ИмяЭкспорта) в колбэке.next/imageВ компоненте HeavyComponent вы показываете:
<Image> с ленивой загрузкой по умолчанию,priority),Пример:
import Image from 'next/image';
import Link from 'next/link';
export default function HeavyComponent() {
return (
<div>
<Image
src="/big-photo.jpg"
alt="Example"
width={600}
height={400}
loading="lazy" // по умолчанию в Next.js и так lazy
/>
<Image
src="/hero.jpg"
alt="Main banner"
width={1200}
height={600}
priority // отключает lazy, грузит сразу
/>
<Link href="/about" prefetch={false}>
О нас
</Link>
</div>
);
}
Принципы:
priority только для критически важных изображений (герой, главный баннер).Link:
prefetch={false} отключает это поведение (например, если страница тяжелая).Исходя из ваших примеров, можно сформулировать стратегию:
dynamic:
ssr: false для браузер‑только компонентов;loading, чтобы UX был плавным.next/image везде, где можно;width/height;priority.prefetch.Модуль 18-lazy-loading в вашем проекте — готовый практический справочник по этим приёмам. Этого раздела должно хватить, чтобы вспомнить и переиспользовать все основные паттерны ленивой загрузки и оптимизации фронтенда в Next.js.