Каждый раз, когда я нажимаю на ссылку для перехода по этому маршруту, загрузка этой страницы в Next.js занимает почти 3-4 секунды.

Вопрос или проблема

Страницы загружаются медленно/перенаправление не происходит немедленно после того, как я нажимаю на ссылку, чтобы открыть динамически сформированные страницы.

*это приложение/appliance-service/[slug]/page.tsx, которое я пытаюсь открыть
*

import React, { Suspense } from 'react';
import PageContent from './PageContent';
import { LocalBusiness, WebSite, SearchAction, PostalAddress, GeoCoordinates, Person, Organization, OpeningHoursSpecification, FAQPage, WithContext } from 'schema-dts';
import SchemaScripts from './SchemaScripts';
import MetadataGenerator from './MetadataGenerator';

interface PageParams {
  slug: string;
}

// Объекты JSON-LD Schema.org
const localBusinessJsonLd: WithContext<LocalBusiness> = {
временно удалено
}
// Вспомогательные функции для получения данных

const Page = async ({ params }: { params: PageParams }) => {
    return (
      <>
        <PageContent slug={params.slug} />

        {/* Скрипты схемы */}

        <SchemaScripts
          slug={params.slug}
          localBusinessJsonLd={localBusinessJsonLd}
          websiteJsonLd={websiteJsonLd}
          personJsonLd={personJsonLd}
          organizationJsonLd={organizationJsonLd}
        />
      </>
    );
  }

export async function generateMetadata({ params }: { params: PageParams }) {
  return await MetadataGenerator({ slug: params.slug });
}

export default Page;

это компонент приложения/appliance-service/PageContent, который используется в вышеупомянутом page.tsx


"use client";
import React, { useMemo, useRef } from 'react';
import useSWR from 'swr';
import RefrigeratorRepairBanner from '../../components/appliance-service-ui/Banner';
import ServiceFeatures from '../../components/appliance-service-ui/ServiceFeature';
import ApplianceFaq from '@/app/components/appliance-service-ui/ApplianceFaq';
import ContactSection from '../../components/appliance-service-ui/ContactSection';
import ServiceCenterLocation from "@/app/components/appliance-service-ui/ServiceCenterLocation";
import ApplianceCard from '@/app/components/ApplianceCard';
import WhyChooseUs from "@/app/components/appliance-service-ui/WhyChooseUs";
import { ImageOnLeft } from "@/app/components/appliance-service-ui/ImageOnLeft";
import { ImageOnRight } from "@/app/components/appliance-service-ui/ImageOnRight";
import { ProblemSection } from "@/app/components/appliance-service-ui/ProblemSection";
import { RepairParts } from "@/app/components/appliance-service-ui/RepairParts";
import { TypesOfAppliance } from "@/app/components/appliance-service-ui/TypesOfAppliance";
import LogoSliderAppliance from '@/app/components/appliance-service-ui/LogoSliderAppliance';
import ServiceAreasAppliance from '@/app/components/appliance-service-ui/ServiceAreaAppliance';
import NotFoundPage from '@/app/not-found';
import BannerSkeleton from './components/RefrigeratorRepairBannerSkeleton';
interface PageContentProps {
  slug: string;
}

type ComponentType =
  | "TypesOfAppliance"
  | "ImageOnLeft"
  | "ImageOnRight"
  | "ProblemSection"
  | "RepairParts"
  | "ContactSection";

// Функция для получения данных
const fetcher = (url: string) => fetch(url, { cache: 'no-cache' }).then(res => {
  if (!res.ok) {
    throw new Error('Ответ сети не был успешным');
  }
  return res.json();
});

const PageContent: React.FC<PageContentProps> = ({ slug }) => {
  const { data: pageData, error: pageError } = useSWR(`/api/pages/${slug}`, fetcher);
  const { data: locationsData } = useSWR(`/api/pages/items`, fetcher);
  const { data: slugsData } = useSWR(`/api/pages`, fetcher);

  const loading = !pageData && !pageError; // Состояние загрузки
  const notFound = pageError && pageError.message === '404'; // Состояние не найдено
  const decodedJoditContent = useRef('');

  // Декодирование содержимого Jodit
  if (pageData && pageData.content) {
    decodedJoditContent.current = pageData.content;
  }

  // Мемоизируем карту компонентов, чтобы избежать ее пересоздания на каждом рендере
  const componentMap = useMemo(() => ({
    TypesOfAppliance,
    ImageOnLeft,
    ImageOnRight,
    ProblemSection,
    RepairParts,
    ContactSection,
  }), []);

  // Мемоизируем функцию getComponentByType
  const getComponentByType = useMemo(() => (type: ComponentType) => {
    return componentMap[type] || null;
  }, [componentMap]);

  // Мемоизируем isEmptyContent, чтобы предотвратить ненужные перерасчеты
  const isEmptyContent = useMemo(() => (content: string) => {
    return content.trim() === '<p><br></p>' || content.trim() === '';
  }, []);

  // Обрабатываем состояния загрузки и не найдено
  if (loading) return <BannerSkeleton />;
  if (notFound) return <NotFoundPage />;

  // Убедитесь, что pageData определено перед деструктурированием
  if (!pageData) {
    return <NotFoundPage />;
  }

  const locations = locationsData?.locations.map((location: { name: string }) => location.name) || [];
  const slugs = slugsData?.map((page: { slug: string }) => page.slug) || [];

  // Деструктурируем свойства из pageData безопасно
  const { banner, components, faqs, appliance, whyChooseUs, brandName } = pageData || {};

  return (
    <div>
      <RefrigeratorRepairBanner
        heading={banner.title}
        imageSrc={banner.imageUrl}
        description={banner.description}
        alt={banner.alt}
      />
      <ServiceFeatures />
      <WhyChooseUs
        appliance={appliance}
        sectionHeading={whyChooseUs.sectionHeading}
        sectionContent={whyChooseUs.sectionContent}
        expertiseTitle={whyChooseUs.expertiseTitle}
        expertiseDescription={whyChooseUs.expertiseDescription}
        availabilityTitle={whyChooseUs.availabilityTitle}
        availabilityDescription={whyChooseUs.availabilityDescription}
        techniciansTitle={whyChooseUs.techniciansTitle}
        techniciansDescription={whyChooseUs.techniciansDescription}
      />

      <div className="max-w-7xl 2xl:container mx-auto grid grid-cols-1 lg:grid-cols-[30%_70%] mt-6">
        <div className="order-last lg:order-first w-full">
          <ServiceCenterLocation
            brandName={brandName}
            appliance={appliance}
            location={locations}
            slugs={slugs}
          />
        </div>
        <div className="flex-grow overflow-y-auto">
          {!isEmptyContent(decodedJoditContent.current) && (
            <div
              className="jodit-content"
              dangerouslySetInnerHTML={{ __html: decodedJoditContent.current }}
            />
          )}
          {components?.map((component: { type: string; _id: any; props: any }) => {
            const Component = getComponentByType(component.type as ComponentType);
            return Component ? <Component key={component._id} {...component.props} /> : null;
          })}

          <ServiceAreasAppliance location={locations} appliance={appliance} />
        </div>
      </div>

      <LogoSliderAppliance appliance={appliance} />
      <div className="max-w-7xl 2xl:container mx-auto">
        <ApplianceFaq faqs={faqs} />
      </div>
      <ApplianceCard />
    </div>
  );
};

export default PageContent;

Когда я нажимаю на ссылки в навигационной панели, чтобы открыть эту страницу, это занимает много времени. Я понимаю, что требуется время для загрузки страницы, данные для которой поступают из бэкенда, но это перенаправление не происходит мгновенно, мне нужно почти 2 секунды просто для перенаправления на этот URL.

Буду признателен за любую помощь.

Ответ или решение

Ситуация, когда переход по ссылке на странице приложения Next.js занимает 3-4 секунды, может быть результатом ряда факторов, как технических, так и связанных с архитектурой вашего приложения. Давайте рассмотрим основные элементы, которые могут влиять на скорость загрузки, и предложим возможные решения.

1. Архитектура приложения и рендеринг страниц

Используйте предварительную выборку данных

Ваша страница (page.tsx) выполняет асинхронные запросы к API для загрузки данных. Это дело, конечно, важно, однако ждать ответа от сервера может занять время. Вы можете использовать метод getStaticProps или getServerSideProps, если в этом есть смысл для вашего случая. Это позволит получить данные заранее, что может значительно ускорить время отклика по сравнению с тем, когда данные загружаются после инициализации компонента.

Префетчинг

Если данные, необходимые для отображения страницы, часто не меняются, подумайте о предзагрузке данных (prefetch), которая может помочь ускорить время загрузки. Эта функциональность Next.js позволит загружать данные до взаимодействия пользователя с ссылкой.

2. Оптимизация компонента PageContent

Использование метода useMemo

Вы уже используете useMemo для кэширования результатов, и это хорошая практика. Однако убедитесь, что вы эффективно используете эту оптимизацию. Проверьте, не является ли это потенциальной причиной для лишних вычислений при каждом перерисовывании.

Lazy Loading

Подумайте о использовании ленивой загрузки (React.lazy и Suspense) для компонентов, которые не нужны сразу на загрузке. Это поможет разбить ваш код на меньшие части и загружать только необходимые элементы по мере необходимости, тем самым уменьшая первоначальный размер загрузки.

3. Оптимизация API-запросов

Использование кэша

В вашем коде используется useSWR с параметром cache: 'no-cache', что приводит к тому, что каждый раз осуществляется новый запрос к серверу. Настройка кэша для данных поможет избежать лишних запросов. Мы рекомендуем использовать подход, при котором данные хранятся на стороне клиента и обновляются только при необходимости (например, каждые несколько минут или при изменении данных).

4. Настройка современных подходов к маршрутизации

Анимация переходов

Добавьте анимации переходов или спиннеры. Это поможет улучшить восприятие задержки. Если пользователь видит интерфейсный элемент, показывающий прогресс, это может компенсировать задержку в переходах.

5. Анализ производительности

Используйте инструменты мониторинга

Используйте инструменты анализа производительности, такие как Lighthouse, чтобы выявить узкие места и проблемы, которые могут замедлять загрузку. Это даст вам представление о том, какие элементы приложения требуют оптимизации.

Заключение

Скорость загрузки страниц — это критически важный аспект пользовательского опыта, и улучшение его должно стать частью вашей стратегии разработки. Применяя описанные выше подходы, вы сможете ускорить переходы между страницами и обеспечить пользователям комфортное взаимодействие с вашим приложением.

Не забудьте протестировать изменения и следовать за метриками производительности, чтобы убедиться, что внесенные улучшения работают на практике.

Оцените материал
Добавить комментарий

Капча загружается...