Простые переходы по маршруту в Next.js

Я собираюсь поделиться простым подходом к переходам страниц в Next.js на основе хуков. Эта статья посвящена не CSS, а тому, как писать пользовательские хуки react.
Для выполнения CSS-магии мы будем использовать https://mui.com/material-ui/transitions/.

Первым шагом будет определение способа перехвата рендеринга страницы в Next.js, что можно сделать, создав файл _app.js в папке pages.

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}
export default MyApp
Вход в полноэкранный режим Выход из полноэкранного режима

https://nextjs.org/docs/advanced-features/custom-app
Next.js использует компонент App для инициализации страниц. Вы можете переопределить его и управлять инициализацией страницы.

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

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

import { useEffect, useState } from 'react';

export default function useSimpleRouteTransition({ delay, children }) {
  const [transitionEnd, setTransitionEnd] = useState(true);
  const [displayChildren, setDisplayChildren] = useState(children);

  useEffect(() => {
    setTransitionEnd(false);
    const t = setTimeout(() => {
      setDisplayChildren(children);
      setTransitionEnd(true);
    }, delay);

    return () => {
      clearTimeout(t);
    };
  }, [children]);

  return {
    displayChildren,
    transitionEnd,
  };
}

Вход в полноэкранный режим Выйти из полноэкранного режима

Для инициализации требуется два параметра:

Давайте проанализируем код.

const [transitionEnd, setTransitionEnd] = useState(true);
const [displayChildren, setDisplayChildren] = useState(children);
Вход в полноэкранный режим Выход из полноэкранного режима

Мы определяем внутреннее состояние с true в качестве начального значения и создаем копию children.

Погружаемся в код useEffect.

useEffect(() => {
  setTransitionEnd(false);
  const t = setTimeout(() => {
    setDisplayChildren(children);
    setTransitionEnd(true);
  }, delay);

  return () => {
    clearTimeout(t);
  };
}, [children]);
Вход в полноэкранный режим Выход из полноэкранного режима

Каждый раз, когда children меняется, ставится в очередь setTimeout, который обновляет новых детей после установленной нами delay. Чтобы представить это действие, мы также переключим наш внутренний transitionEnd с false на true.
Наконец, таймаут очищается всякий раз, когда компонент размонтируется.

Если собрать все вместе в компонент Layout, он должен выглядеть следующим образом:

import Link from 'next/link';
import { Box, Container, Stack, Fade } from '@mui/material';
import useSimpleRouteTransition from '@/hooks/useSimpleRouteTransition';

export default function Layout({ children }) {
  const { transitionEnd, displayChildren } = useSimpleRouteTransition({
    delay: 1000,
    children,
  });

  return (
    <Container maxWidth="lg">
      <Box
        sx={{
          flexFlow: 'column nowrap',
        }}
      >
        <Box mt={10} mb={0}>
          <h1>Page transitions with Next.js</h1>
        </Box>
      </Box>
      <Stack direction={'row'} spacing={2}>
        <Link href="/">index</Link>
        <Link href="/blog">blog</Link>
        <Link href="/links">Links</Link>
      </Stack>
      <Box sx={{ bgcolor: 'green', p: 2 }}>
        <Fade in={transitionEnd} timeout={1000}>
          <div>{displayChildren}</div>
        </Fade>
      </Box>
      <Box sx={{ bgcolor: 'darkblue', p: 2 }}>Footer</Box>
    </Container>
  );
}
Вход в полноэкранный режим Выход из полноэкранного режима

Давайте рассмотрим реализацию.

const { transitionEnd, displayChildren } = useSimpleRouteTransition({
    delay: 1000,
    children,
  });
Вход в полноэкранный режим Выход из полноэкранного режима

Мы вызываем наш пользовательский хук с delay: 1000 и children, которые мы получаем от нашего родительского компонента. Оттуда мы получаем displayChildren и transitionEnd.

<Fade in={transitionEnd} timeout={1000}>
  <div>{displayChildren}</div>
</Fade>
Вход в полноэкранный режим Выход из полноэкранного режима

В нашем представлении всегда показывается displayChildren вместо children. Мы обернули это представление в компонент Fade, который мы устанавливаем с помощью transitionEnd для достижения управляемого затухания.

Вот и все! Дайте мне знать, если это работает для вас.

Вы можете найти весь исходный код на GitHub:
https://github.com/calinalexandru/next-js-router-transitions

Оцените статью
devanswers.ru
Добавить комментарий