Вопрос или проблема
Воспроизведение:
https://codesandbox.io/p/devbox/next-js-fxis37
В воспроизведении вы увидите навигацию с разворачивающимся подменю. Например, нажмите home
, и вы увидите раскрывающееся подменю.
Вы увидите в NavItem.tsx
, что я использую React.useState(...)
. Поэтому мне пришлось добавить use client
в верхнюю часть файла.
Теперь, когда сервер возвращает страницу, NavItem
не будет отображаться, что плохо для SEO. Навигация – это очень важная вещь, которую нужно включить в SSR.
Как я могу обновить свою навигацию, чтобы SSR отображал важные элементы, при этом сохраняя реактивные и состоянии функции?
Ответ или решение
В современном веб-разработке создание приложений с использованием React в сочетании с серверным рендерингом (SSR) может представлять собой определенные сложности, особенно когда речь идет о компонентах, использующих состояние, таких как useState
. Рассмотрим вашу ситуацию более детально и предложим решения, позволяющие оптимально использовать возможности SSR, одновременно сохраняя реактивность компонентов.
Проблема
В вашем коде используется хук React.useState(...);
, который предназначен для управления состоянием компонентов. Однако этот хук можно применять только в клиентских компонентах, что требует добавления директивы use client
в начало вашего файла NavItem.tsx
. Это, в свою очередь, приводит к том, что при первичном рендеринге страницы на сервере компонент NavItem
не появляется, что негативно сказывается на индексации страниц и SEO.
Решение
Для достижения поставленной цели — обеспечить наличие важной навигации в SSR, сохранив при этом интерактивные функции — можно рассмотреть несколько подходов:
1. Разделение компонентов
Создайте два компонента: один, который будет рендериться на сервере (например, NavItemStatic
), и другой, клиентский компонент, который будет управлять состоянием (например, NavItemDynamic
).
// NavItemStatic.tsx
export const NavItemStatic = () => (
<div>
<button>Home</button>
<ul>
<li>Submenu Item 1</li>
<li>Submenu Item 2</li>
</ul>
</div>
);
// NavItemDynamic.tsx
"use client";
import React from 'react';
const NavItemDynamic = () => {
const [isOpen, setIsOpen] = React.useState(false);
return (
<div>
<button onClick={() => setIsOpen(!isOpen)}>Home</button>
{isOpen && (
<ul>
<li>Submenu Item 1</li>
<li>Submenu Item 2</li>
</ul>
)}
</div>
);
};
В вашем основном компоненте можно будет использовать оба этих компонента, как показано ниже:
// App.tsx
import { NavItemStatic } from './NavItemStatic';
import { NavItemDynamic } from './NavItemDynamic';
const App = () => (
<nav>
<NavItemStatic />
<NavItemDynamic />
</nav>
);
В этом случае на сервере будут рендериться статические элементы, что положительно скажется на SEO, а интерактивные элементы будут загружены на клиенте, обеспечивая необходимую динамику.
2. Использование контекста или глобального состояния
Если ваш проект достаточно велик и требует большей сложности в управлении состоянием, рассмотрите возможность использования контекста или библиотек для управления состоянием, таких как Redux или Zustand. Это позволит вам хранить состояние на уровне приложения и использовать его в разных компонентах, как клиентских, так и серверных.
3. SEO-оптимизация
Важно помнить, что SEO — это не только о рендеринге навигации, но и о том, что контент на странице отвечает ожиданиям пользователей и поисковых систем. Убедитесь, что все важные ссылки и заголовки присутствуют и имеют семантическую разметку.
Заключение
Комбинируя подходы к созданию компонентов и оптимизацию состояния, вы сможете добиться балансировки между серверным рендерингом и интерактивностью вашего приложения. Не забывайте тестировать ваше решение и следить за его воздействием на производительность и SEO. Это не только улучшит восприятие пользователями вашего веб-приложения, но и поможет вам избежать проблем с индексацией в дальнейшем.