使用 React 动画删除数组对象

问题描述 投票:0回答:1

我已经为此工作了几个小时,但我被困住了。我已经剥离了我正在处理的代码,并且我将描述不起作用的部分。我在下面有它,包括所有进口。

我试图在单击芯片的 x 时播放动画(现在是淡入淡出)。我已经能够将淡入组合在一起,因此当我输入新名称时,它会在到达时淡入(谢谢 useEffect()!)。

现在,我注意到动画在退出时不会播放(我认为这是因为它的引用已从数组中删除,这影响了 map() 的调用)。我真正想做的是让对象动画消失,然后从数组中删除。

当我尝试使用 setTimeout 等待动画完成时,它开始将动画应用到数组中的相邻元素。

我确实知道为什么会发生这种情况,但我根本不知道如何将我的代码转变为反应范式,并摆脱我的堆栈/回调思维模式,并设置反应来执行我要求的操作。我可以得到一点帮助吗?

谢谢 克里斯

import TextField from '@mui/material/TextField';
import { useRef, useState } from 'react';
import Container from '@mui/material/Container';
import Paper from '@mui/material/Paper';
import Chip from '@mui/material/Chip';
import { styled } from '@mui/material/styles';
import { useEffect } from 'react';
import {Transition} from 'react-transition-group';


const startList = [
    {name:"Ethan Anderson"},{name:"Olivia Brooks"},{name:"Mason Carter"},{name:"Ava Davis"}
    ];

function Student({student, hDelete}) {
    const nodeRef = useRef(null);
    const [inProp, setIn] = useState(false);
    useEffect(() => {
        setIn(true);
    }, [] );
    const handleDelete=() => {
        setIn(false);
        setTimeout(() => hDelete(student),320)
    }
    const duration = 300;

    const defaultStyle = {
        transition: `opacity ${duration}ms ease-in-out`,
        opacity: 0,
    }

    const transitionStyles = {
        entering: { opacity: 1 },
        entered:  { opacity: 1 },
        exiting:  { opacity: 0 },
        exited:  { opacity: 0 },
    };

    return (
<Transition nodeRef={nodeRef} in={inProp} appear="true" timeout={duration}>
    {state => (
        <ListItem style={{...defaultStyle,...transitionStyles[state]}}>
            <Chip
                variant="solid"
                size="small"
                sx={{
                    height: 'auto',
                    '& .MuiChip-label': {
                        display: 'block',
                        whiteSpace: 'normal',
                    },
                }}
                label={`${student.name}`}
                onDelete={handleDelete}
                />
        </ListItem>
    )}
        </Transition>
    )
}


const ListItem = styled('li')(({ theme }) => ({
    margin: theme.spacing(0.5),
 }));

export default function CreateStudentForm() {
    const nameRef = useRef(null);
    const [people, setPeople] = useState([...startList]);
    const handleKeyDown = (event, nextRef) => {
        if (event.key === 'Enter') {
            event.preventDefault();
            console.log(nextRef.current.id);
            if (nextRef.current.id !== "firstName") {
                nextRef.current.focus();
            } else {
                let myObj = {
                    name: nameRef.current.value,
                };
                nameRef.current.value = '';
                let newPeople = JSON.parse(JSON.stringify(people));
                newPeople.push(myObj);
                setPeople(newPeople);
                console.log(newPeople);
                nameRef.current.focus();
            }
        }
    };
    const handleDelete = (person) => {
        let newPeople = JSON.parse(JSON.stringify(people));
        let idx = people.findIndex((e) => e === person);
        newPeople.splice(idx,1);
        setPeople(newPeople);
    };


    return (
<Container maxWidth="md">
    <TextField
        fullWidth
        id="firstName"
        label="First Name"
        size="small"
        margin="normal"
        inputRef={nameRef}
        onKeyDown={(e) => handleKeyDown(e, nameRef)}
    />
    <Paper
        sx={{
            display: 'flex',
            justifyContent: 'center',
            flexWrap: 'wrap',
            listStyle: 'none',
            p: 0.5,
            m: 0,
            }}
            component="ul"
        >
        {people.map((data, i) => (
            <Student key={i} student={data} hDelete={handleDelete}/>
            )
        )}

    </Paper>
</Container>
    );
}   



css reactjs animation react-hooks react-transition-group
1个回答
0
投票

您似乎正在尝试在从列表中删除 Chip 时实现淡出动画。您面临的问题是,当您使用 setTimeout 等待动画完成后再从列表中删除项目时,动画会影响相邻元素。

为了解决这个问题,您可以利用react-transition-group中的Transition组件来单独管理每个Chip的动画状态。您可以通过以下方式修改代码来实现此目的:

    import TextField from '@mui/material/TextField';
import { useRef, useState } from 'react';
import Container from '@mui/material/Container';
import Paper from '@mui/material/Paper';
import Chip from '@mui/material/Chip';
import { styled } from '@mui/material/styles';
import { useEffect } from 'react';
import { Transition } from 'react-transition-group';

const startList = [
    { name: "Ethan Anderson" }, { name: "Olivia Brooks" }, { name: "Mason Carter" }, { name: "Ava Davis" }
];

function Student({ student, hDelete }) {
    const nodeRef = useRef(null);
    const [inProp, setIn] = useState(true);

    useEffect(() => {
        setIn(true);
    }, []);

    const handleDelete = () => {
        setIn(false);
    }

    const duration = 300;

    const defaultStyle = {
        transition: `opacity ${duration}ms ease-in-out`,
        opacity: 0,
    }

    const transitionStyles = {
        entering: { opacity: 1 },
        entered: { opacity: 1 },
        exiting: { opacity: 0 },
        exited: { opacity: 0 },
    };

    return (
        <Transition nodeRef={nodeRef} in={inProp} timeout={duration}>
            {state => (
                <ListItem style={{ ...defaultStyle, ...transitionStyles[state] }}>
                    <Chip
                        variant="solid"
                        size="small"
                        sx={{
                            height: 'auto',
                            '& .MuiChip-label': {
                                display: 'block',
                                whiteSpace: 'normal',
                            },
                        }}
                        label={`${student.name}`}
                        onDelete={() => {
                            handleDelete();
                            setTimeout(() => hDelete(student), duration); // Remove after animation
                        }}
                    />
                </ListItem>
            )}
        </Transition>
    )
}

const ListItem = styled('li')(({ theme }) => ({
    margin: theme.spacing(0.5),
}));

export default function CreateStudentForm() {
    const nameRef = useRef(null);
    const [people, setPeople] = useState([...startList]);

    const handleKeyDown = (event, nextRef) => {
        if (event.key === 'Enter') {
            event.preventDefault();
            if (nextRef.current.id !== "firstName") {
                nextRef.current.focus();
            } else {
                let myObj = {
                    name: nameRef.current.value,
                };
                nameRef.current.value = '';
                setPeople(prevPeople => [...prevPeople, myObj]);
                nameRef.current.focus();
            }
        }
    };

    const handleDelete = (person) => {
        setPeople(prevPeople => prevPeople.filter(p => p !== person));
    };

    return (
        <Container maxWidth="md">
            <TextField
                fullWidth
                id="firstName"
                label="First Name"
                size="small"
                margin="normal"
                inputRef={nameRef}
                onKeyDown={(e) => handleKeyDown(e, nameRef)}
            />
            <Paper
                sx={{
                    display: 'flex',
                    justifyContent: 'center',
                    flexWrap: 'wrap',
                    listStyle: 'none',
                    p: 0.5,
                    m: 0,
                }}
                component="ul"
            >
                {people.map((data, i) => (
                    <Student key={i} student={data} hDelete={handleDelete} />
                ))}
            </Paper>
        </Container>
    );
}

在此修改中,我从 Student 组件中的 handleDelete 函数中删除了 setTimeout。相反,在将 inProp 设置为 false 后立即调用 hDelete 函数。这可确保仅在该特定芯片的淡出动画完成后才能从列表中删除该项目。

© www.soinside.com 2019 - 2024. All rights reserved.