⏭️ Как быстро разобраться в Next.js 14: 5 советов опытного фронтендера
Next.js – мощный фреймворк для создания веб-приложений на React: он поддерживает статическую генерацию сайтов, серверный и клиентский рендеринг. Это делает его идеальным выбором для проектов, которым необходима высокая производительность, SEO-дружественность и масштабируемость. Делимся пятью советами, которые помогут быстро разобраться в тонкостях работы с изображениями, переменными окружения, кэшированием и управлением компонентами в Next.js.
Оптимизация изображений в Next.js
Скорость загрузки изображений играет критическую роль в любом веб-приложении – особенно если изображений много. Next.js предоставляет встроенные функции оптимизации, которые могут значительно улучшить время загрузки и пользовательский опыт. Однако у начинающих разработчиков часто возникают сложности с эффективной реализацией этих функции, поскольку подходы к работе с локальными и удаленными изображениями заметно различаются.
Локальные изображения
При использовании локальных изображений в Next.js не нужно указывать атрибуты width
и height
– Next.js автоматически вычисляет эти значения, предотвращая искажение страницы. Просто поместите изображения в директорию public, импортируйте их и выполните рендеринг с помощью компонента next/image
. Можно использовать placeholder="blur"
для показа размытых версий изображений, пока картинки не загрузятся полностью:
import Image from "next/image"; import example from "@/public/example.jpg"; export default function Home() { return ( <main className="flex min-h-screen flex-col items-center justify-center"> <h1>Название изображения</h1> <Image src={example} alt="Описание изображения" placeholder="blur"/> </main> ); }
Удаленные изображения
При загрузке удаленных изображений необходимо указывать ширину и высоту изображений:
import Image from "next/image"; import example from "@/public/example.jpg"; export default function Home() { const remoteImg = ( <Image src="https://cdnservice.com/my-media/example.jpg" alt="Описание изображения" width={500} height={300} /> ); return ( <main className="flex min-h-screen flex-col items-center justify-center"> <h1>Название изображения</h1> {remoteImg} </main> ); }
Если нужно показывать размытые плейсхолдеры, придется установить специальные пакеты – sharp и plaiceholder (именно так, это не опечатка):
npm install sharp plaiceholder @plaiceholder/next
И создать вспомогательную функцию:
import placeholder from 'placeholder'; import sharp from 'sharp'; export async function getBase64(url) { const res = await fetch(url); const buffer = await res.arrayBuffer(); const base64 = await placeholder(buffer); return base64; }
Функция getBase64 загружает изображение по указанному URL, преобразует его в формат ArrayBuffer, и использует библиотеку plaiceholder для создания размытой версии изображения:
import { getBase64 } from './utils/getBase64'; export default async function Home() { const blurData = await getBase64('https://my-cdn.com/my-account/example.jpg'); return ( <Image src="https://my-cdn.com/my-account/example.jpg" width={800} height={600} alt="Описание изображения" placeholder="blur" blurDataURL={blurData} /> ); }
Использование переменных окружения
Будьте осторожны с префиксом NEXT_PUBLIC
– он раскрывает всю информацию в браузере:
NEXT_PUBLIC_API_URL=https://api.example.com
Без этого префикса переменная будет доступна только в серверной среде. Это особенно важно для API-ключей и других конфиденциальных данных, которые не должны передаваться пользователям:
API_SECRET_KEY=your-secret-key
Кэширование в среде разработке и в продакшене
Next.js использует разные подходы к кэшированию в зависимости от среды (разработка или продакшн):
- В режиме разработки страницы обновляются динамически по умолчанию, при каждой перезагрузке.
- В продакшене по умолчанию создаются статические страницы, которые генерируются при сборке и остаются неизменными до следующей сборки.
Управлять кэшированием можно с помощью опции revalidate
для инкрементальной статической регенерации или force-dynamic
для постоянного получения свежих данных. В первом примере страница будет обновляться каждые 5 секунд, во втором случае статическая оптимизация отключается, обновление будет происходить динамически:
// Повторная валидация каждые 5 секунд export const revalidate = 5; // Принудительное динамическое получение данных export const dynamic = 'force-dynamic';
Получение данных в серверных компонентах
Вместо того, чтобы создавать отдельный API-маршрут для получения данных, а затем вызывать этот маршрут из серверного компонента, рекомендуется получать данные напрямую. Этот подход позволяет Next.js оптимизировать кэширование и повторное использование данных в нескольких серверных компонентах:
export default async function Home() { const res = await fetch('https://api.example.com/jokes/random'); const data = await res.json(); return <div>{data.joke}</div>; }
Если нужно использовать одну и ту же логику получения данных в нескольких местах, нужно создать серверное действие:
// server/getJoke.js import { server } from 'next/server'; export async function getJoke() { const res = await fetch('https://api.example.com/jokes/random'); const data = await res.json(); return data; } // Home.js import { getJoke } from '../server/getJoke'; export default async function Home() { const joke = await getJoke(); return <div>{joke.joke}</div>; }
Серверные и клиентские компоненты
Next.js использует два типа компонентов – серверные и клиентские.
Серверные компоненты
- По умолчанию все страницы в Next.js являются серверными компонентами.
- Они выполняются на сервере и отправляют готовый HTML клиенту.
- Могут иметь прямой доступ к серверным ресурсам (базе данных, файловой системе), но не имеют доступа к клиентскому API (useState, useEffect и т. д.)
- Отличаются быстрой начальной загрузкой и SEO-дружественностью.
- Серверные компоненты могут включать в себя клиентские (для интерактивности).
Клиентские компоненты
- Выполняются на стороне пользователя, могут использовать браузерные API (например, localStorage).
- Они могут быть интерактивными (формы, кнопки, анимации) и использовать все возможности React в браузере.
- Подходят для создания компонентов, которые должны обновляться без перезагрузки страницы.
- Чтобы сделать компонент клиентским, нужно добавить директиву
"use client"
:
"use client"; import { useState } from "react"; export default function ClientComponent() { const [count, setCount] = useState(0); return ( <div> <p>Счет: {count}</p> <button onClick={() => setCount(count + 1)}>Увеличить счет</button> </div> ); }
Next.js позволяет легко комбинировать серверные и клиентские компоненты, чтобы готовое приложение могло обеспечить наилучшую производительность и пользовательский опыт:
// Клиентский компонент 'use client'; import { useState } from 'react'; export default function ClientComponent() { const [count, setCount] = useState(0); return ( <button onClick={() => setCount(count + 1)}> Count: {count} </button> ); } // Серверный компонент import ClientComponent from '../components/ClientComponent'; export default function Home() { return ( <div> <ClientComponent /> </div> ); }
Особенности взаимодействия компонентов
Вложенность
- Когда вы рендерите клиентский компонент внутри серверного, он остается клиентским.
- Все дочерние компоненты клиентского компонента автоматически становятся клиентскими, даже без директивы
"use client"
.
Работа с провайдерами
При работе с провайдерами (например, для тем), важно правильно обрабатывать дочерние компоненты, чтобы они сохраняли свой статус серверных или клиентских компонентов. В этом примере Theme
остается серверным компонентом:
// theme.js import { ThemeProvider } from 'styled-components'; export default function Theme({ children }) { return <ThemeProvider theme={{}}>{children}</ThemeProvider>; } // layout.js import Theme from '../components/theme'; export default function Layout({ children }) { return ( <Theme> {children} </Theme> ); }
В заключение
Мы рассмотрели ключевые аспекты работы с Next.js, которые обычно вызывают затруднения у начинающих разработчиков. Понимание этих базовых концепций закладывает достаточный фундамент для дальнейшего изучения и использования более продвинутых функций фреймворка.
При подготовке статьи использовалась информация из видео:
💻 Для тех, кто хочет войти во frontend-разработку
Запустили базовый курс Frontend Basic с фокусом на реальные задачи:
- Создадите интернет-магазин с нуля
- Освоите связку HTML + CSS + JavaScript
- Научитесь работать с React и Git
- Получите код-ревью от разработчиков из Газпромбанка
26 уроков, 28 заданий, 2 месяца практики. Доступ к материалам — навсегда.