Как создать анимацию бесконечного слайдера в Next.js и как управлять классами в массиве объектов?

Изучая Next.js и анимацию, у меня возникли несколько вопросов. Я работаю над неинтерактивным бесконечным слайдером для иконок криптовалюты. Мне удалось реализовать бесконечность и анимацию прокрутки, однако я уверен, что можно сделать это лучше. Я столкнулся с задачей выделения первого элемента: он должен иметь более яркий фон и увеличенный размер иконки. При этом первый элемент должен анимированно терять класс `main` и выходить за пределы видимости пользователя, а второй элемент — анимированно занимать его место и получать класс `main`. Бесконечная прокрутка работает, но мне не удается выяснить, как реализовать добавление классов в компоненте `pages`. <br/> <br/> У меня также есть вопрос по поводу использования `key`. В консоли появляется предупреждение о том, что `key` не уникален в самом последнем `return`. Я не понимаю, зачем нужен `key` и как это исправить. Кроме того, я хотел бы узнать, как отключить двойной вызов `setTimeout` в режиме разработки. <br/> <br/> <pre><code class="javascript">import { StyledCardList, StyledSecondaryCard } from './styled'
    import React from "react";
    import { useState, useEffect } from "react";
    import cardDetails from "./swiperconfig"
         
    const TRANSITION_DURATION = 1500;
      
    export const Carousel = () =&gt; {
const [pages, setPages] = useState([])
const [offset, setOffset] = useState(0)
const [transitionDuration, setTransitionDuration] = useState(TRANSITION_DURATION)

const handleTransitionEnd = () =&gt; {
  setOffset(0);
  setTransitionDuration(0);
  console.log(offset)
}
useEffect(() =&gt; {
  if (transitionDuration === 0) {
    setTimeout(() =&gt; {
      setTransitionDuration(TRANSITION_DURATION)
    }, TRANSITION_DURATION)
  }
}, [transitionDuration
  • 1 октября 2024 г. 15:45
Ответы на вопрос 2
Для создания бесконечного слайдера с анимацией в Next.js, который выделяет текущий элемент, вам нужно будет обработать несколько аспектов:

1. **Анимация слайдера**: Используйте `useEffect` и `setInterval` для цикличного переключения между элементами.
2. **Управление классами**: Создайте состояние, которое будет отслеживать, какой элемент является "основным", и обновляйте его при прокрутке.
3. **Уникальные ключи для React**: Убедитесь, что ключи уникальны для каждого элемента списка, чтобы избежать предупреждений в консоли.

Ниже приведённый пример, который включает эти аспекты:

```javascript
import React, { useState, useEffect } from "react";
import { StyledCardList, StyledSecondaryCard } from './styled';
import cardDetails from "./swiperconfig";

const TRANSITION_DURATION = 1500;

export const Carousel = () => {
  const [currentIndex, setCurrentIndex] = useState(0);
  const [transitionDuration, setTransitionDuration] = useState(TRANSITION_DURATION);

  useEffect(() => {
    const interval = setInterval(() => {
      setTransitionDuration(TRANSITION_DURATION);
      setCurrentIndex((prevIndex) => (prevIndex + 1) % cardDetails.length);
    }, TRANSITION_DURATION);

    return () => {
      clearInterval(interval);
    };
  }, []);

  const handleTransitionEnd = () => {
    setTransitionDuration(0); // Чтобы избежать перезапусков
  }

  return (
    <StyledCardList onTransitionEnd={handleTransitionEnd} style={{ transitionDuration: `${transitionDuration}ms` }}>
      {cardDetails.map((card, index) => {
        const isActive = index === currentIndex;
        return (
          <StyledSecondaryCard
            key={card.id} // Убедитесь, что card.id уникален
            className={isActive ? 'main' : ''}
            style={{
              transform: isActive ? 'scale(1.2)' : 'scale(1)', // Увеличение для активного элемента
              backgroundColor: isActive ? '#f0f0f0' : 'transparent', // Яркий фон для активного элемента
            }}
          >
            {card.icon}
          </StyledSecondaryCard>
        );
      })}
    </StyledCardList>
  );
}
```

### Объяснение кода:
1. **Состояние `currentIndex`**: Оно отслеживает текущий индекс "основного" элемента.
2. **`setInterval`**: Запускает переключение каждые `TRANSITION_DURATION` миллисекунд для плавной анимации.
3. **Классы и стили**: Используйте условное присваивание классов и инлайн-стили для изменения внешнего вида активного элемента.
4. **Ключи**: Убедитесь, что вы используете уникальные идентификаторы из `cardDetails` в качестве ключей.

### Вопросы:
- **`key`**: React использует `key` для оптимизации рендеринга списков. Ключи помогают React определять, какие элементы изменились, были добавлены или удалены. Убедитесь, что ключи уникальны для каждого элемента в списке.
- **Двойной вызов `setTimeout`**: Если вы видите, что `setTimeout` вызывается дважды в режиме разработки, убедитесь, что функция не вызывается дважды в `useEffect`, и используйте `cleanup` функцию, чтобы очистить таймер.

### Заключение:
Этот код предоставляет основу для реализации анимации бесконечного слайдера и управления классами в массиве объектов. Вы можете настраивать стили, анимации и задержки по своему усмотрению.
Основной проблемой я тут вижу то, что вы в state храните компоненты. Так не делать не надо, в state нужно хранить данные , а из них уже рендерить нужное. Тогда вы и классы сможете гибко добавлять какие надо и что угодно. 

Так же есть вопрос по key, сыпет в консоль предупреждение, что кей не уникален в самом последнем return. Во-первых, я не пойму зачем там key, во-вторых, я не пойму как это пофиксить.
Вы рендерите элементы массива (pages), чтобы отличать их друг от друга, Реакт нужен какой-то идентификатор (подробнее в документации). У вас он как бы есть, но, во-первых, как сказано выше, его ломает то, что вы храните в state уже отрендеренные компоненты, а во-вторых, вы в качестве ключа для всех элементов используете одно и то же значение (cardDetails.id), а оно должно быть уникальным.

как выключить двойной вызов setTimeout в dev mode
Не надо его выключать, надо корректно чистить таймауты, для отлова таких проблем двойной вызов и делают.

Видимо, вы запутались и вам кажется, что вы изучаете Next.js, а на самом деле вы изучаете React (от Next в вашем коде нет абсолютно ничего) и вам явно нужно вернуться к документации и прочитать её от начала и до конца, там есть и ответы на ваши вопросы и примеры.
Похожие вопросы