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

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

Я пытаюсь анимировать список компонентов в React, используя Chakra UI и/или Motion, который создаётся из данных, предоставленных хуком, и хочу, чтобы при добавлении элемента в данные были анимации входа и выхода, но, похоже, что когда данные обновляются, всё просто перезаписывается вместо того, чтобы сначала анимироваться. Вот псевдокод того, что у меня сейчас есть, который, надеюсь, содержит только самое главное:

const item = (itemDetails) => {
    const MotionBox = motion(Box)
    return {
        <MotionBox key="itemDetails.key" initial={false} animate={{opacity: 1, scaleY: 1}} exit={{opacity: 0, scaleY: 0}}>
            //Содержимое элемента
        </MotionBox>
    }
const container = () => {
    const data = useDataHook()
    const [displayedData, setDisplayedData] = useState([])
    const initialRender = useRef(true)
    useEffect(() => {
        if (initialRender.current) {
            setDisplayedData(data)
        } elseif (data.length !== displayedData.length) {
            setDisplayedData(data)
        }
    }, [data, displayedData])
    return {
        <Box>
            <AnimatePresence initial={false}>
                {data.map((item, index) => {
                    return (
                        <Item key={index} itemData={displayedData}/>
                    )
                })
            </AnimatePresence>
        </Box>
    }
}

Я попробовал множество способов, если я не ставлю initial=false, то каждый раз, когда родительский компонент рендерится, всё анимируется снова, из-за чего это выглядит так, словно они мигают (они находятся в аккордеоне, так что не хочу, чтобы они анимировались в начале, только когда добавляются в данные). Но даже без анимации сейчас они не анимируются на выход, если только список не становится пустым, потому что когда данные обновляются, он перерисовывается, как я предполагаю, до того, как анимация может произойти. К сожалению, я не могу предотвратить перерисовку родительского компонента, когда данные не обновлены.

Я пробовал такие вещи, как попытка применить элемент через кнопку применения, чтобы вызвать сервер, но установить переменную состояния, чтобы предотвратить обновление displayedItems до успешного возвращения результата и завершения onAnimationComplete на элементе движения, но это всё равно не анимируется.

Идеально было бы, если бы только новые компоненты элементов анимировались, масштабируясь и появляясь (в идеале плавно сдвигая другие элементы вниз, но я пока не знаю, как это сделать), и когда элемент удаляется, он анимируется при масштабировании и исчезновении. С чем-то подобным, как мне заставить только отдельные элементы, которые я хочу анимировать на или снимать анимацию, делать это вместо всех или ни одного из них? Я могу провести сравнение, чтобы выяснить, какие элементы были добавлены или удалены, но не смог понять, как использовать это, чтобы конкретный элемент анимировался или исчезал.

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

Вопрос: существует ли способ анимации элементов при добавлении или удалении элементов в функции map, где данные обновляются из хуков?

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

Проблема

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

Решение: использование AnimatePresence и состояния

Чтобы анимация работала должным образом, вам необходимо:

  1. Использовать AnimatePresence от Framer Motion для управления анимацией при добавлении и удалении элементов.
  2. Создать механизм контроля состояния, который будет отслеживать новые элементы и удалять исчезающие элементы с анимацией.

Вот пример, как можно улучшить вашу реализацию:

import { motion, AnimatePresence } from 'framer-motion';
import { Box } from '@chakra-ui/react';
import { useEffect, useRef, useState } from 'react';

const MotionBox = motion(Box);

const Item = ({ itemData }) => {
    return (
        <MotionBox
            key={itemData.key}
            initial={{ opacity: 0, scaleY: 0 }}
            animate={{ opacity: 1, scaleY: 1 }}
            exit={{ opacity: 0, scaleY: 0 }}
        >
            {/* Содержимое элемента */}
        </MotionBox>
    );
};

const Container = () => {
    const data = useDataHook(); // Хук для получения данных
    const [displayedData, setDisplayedData] = useState([]);

    useEffect(() => {
        // Устанавливаем новое состояние что-либо изменится
        if (JSON.stringify(data) !== JSON.stringify(displayedData)) {
            setDisplayedData(data);
        }
    }, [data]); // Отслеживаем обновления данных

    return (
        <Box>
            <AnimatePresence>
                {displayedData.map((item) => (
                    <Item key={item.key} itemData={item} />
                ))}
            </AnimatePresence>
        </Box>
    );
};

Объяснение решения

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

  • Сравнение состояния. В useEffect происходит сравнение текущих данных с отображаемыми данными. Если они различаются, происходит обновление состояния displayedData. Это позволяет компонентам плавно анимироваться при изменении.

  • Анимация элементов. Каждый Item анимируется с помощью initial, animate и exit свойств. Состояние анимации задаётся на основе состояния компонента, что позволяет избежать "мигания" при рендеринге.

Заключение

Интеграция анимаций в компоненты React с использованием хуков – это процесс, требующий внимания к деталям и правильного управления состояниями. Применение библиотеки Framer Motion совместно с корректным использованием AnimatePresence позволяет достигать желаемых эффектов анимации при добавлении и удалении элементов списка. Убедитесь, что данные, передаваемые в анимации, обновляются корректно, чтобы предотвратить ненужные перерендеры. Таким образом, ваши UI-элементы будут выглядеть гораздо более плавно и профессионально.

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

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