React与Material UI列表切换时Fade动画无法重复触发的修复咨询
解决Material UI Fade动画仅触发一次的问题
我开发了一个列表组件,点击列表中的兄弟项时,会切换显示带不同文本的元素并触发Material UI的Fade淡入动画。当前问题是动画仅能触发一次,后续点击兄弟项时动画不再生效。以下是我的代码,请告知如何重置控制Fade的selectedElemList状态,使点击兄弟项时能重复触发动画。
import { Fade, Grid, List, ListItemButton, ListItemIcon, ListItemText, Typography } from "@mui/material"; import { useEffect, useState, forwardRef } from "react"; import { Outlet, Link } from "react-router-dom"; import {Box} from "@mui/material" import InBoxIcon from "@mui/icons-material/Inbox"; import DraftsRounded from "@mui/icons-material/Drafts"; const MainContent = () => { const divs = { 0: { text: "hello", pr: "this is pr" }, 1: { text:"second", pr:"this is second pr" } } const [selectedItemList, setselectedItemList] = useState(); const [selectedDivList, setselectedDivList] = useState(); const [selectedElemList, setselectedElemList] = useState(false); const handleSelectedList = ( e, index) => { if(selectedItemList === index){ setselectedItemList() }else{setselectedItemList(index)} setselectedDivList(divs[index]); setselectedElemList((e) => !e); } const Compc = forwardRef((props, ref) => { return( <Box ref={ref} {...props}> <Typography variant="h4" sx={{ textAlign: 'center' }}> {props.text} </Typography> <Typography variant="h6" sx={{ textAlign: 'center' }}> {props.pr} </Typography> </Box> ) }) return ( <> <Grid container direction="row" pt={10} pl={1} pr={1} pb={1}> <Grid item xs={12}> <Typography variant="h2" sx={{textAlign:'center'}}> TITLE </Typography> </Grid> <Grid item xs={6}> <List aria-label="main list element"> <ListItemButton selected={selectedItemList === 0} onClick={ (e) => handleSelectedList(e, 0)}> <ListItemIcon> <InBoxIcon /> </ListItemIcon> <ListItemText primary="Inbox"/> </ListItemButton> <ListItemButton selected={selectedItemList === 1} onClick={ (e) => handleSelectedList(e, 1)}> <ListItemIcon> <DraftsRounded /> </ListItemIcon> <ListItemText primary="Drafts"/> </ListItemButton> </List> </Grid> <Grid item xs={6}> { selectedDivList ? <Fade in={selectedElemList} timeout={600}> <Compc {...selectedDivList} /> </Fade> : '' } </Grid> </Grid> </> ) }; export default MainContent;
解决方案
问题出在selectedElemList的切换逻辑上:单纯取反操作无法保证每次切换列表项时,Fade组件能完整执行"隐藏→显示"的动画流程。连续点击不同列表项时,状态切换太快,组件来不及响应隐藏动作,导致动画不触发。
我们需要通过先隐藏再显示的逻辑重置动画,具体修改如下:
import { Fade, Grid, List, ListItemButton, ListItemIcon, ListItemText, Typography } from "@mui/material"; import { useEffect, useState, forwardRef } from "react"; import { Outlet, Link } from "react-router-dom"; import {Box} from "@mui/material" import InBoxIcon from "@mui/icons-material/Inbox"; import DraftsRounded from "@mui/icons-material/Drafts"; const MainContent = () => { const divs = { 0: { text: "hello", pr: "this is pr" }, 1: { text:"second", pr:"this is second pr" } } const [selectedItemList, setselectedItemList] = useState(); const [selectedDivList, setselectedDivList] = useState(); const [selectedElemList, setselectedElemList] = useState(false); const handleSelectedList = ( e, index) => { // 点击当前选中项时,取消选中并隐藏元素 if(selectedItemList === index){ setselectedItemList(null); setselectedDivList(null); setselectedElemList(false); return; } // 先隐藏元素,等待组件状态更新后再显示,触发动画 setselectedElemList(false); setTimeout(() => { setselectedItemList(index); setselectedDivList(divs[index]); setselectedElemList(true); }, 50); } const Compc = forwardRef((props, ref) => { return( <Box ref={ref} {...props}> <Typography variant="h4" sx={{ textAlign: 'center' }}> {props.text} </Typography> <Typography variant="h6" sx={{ textAlign: 'center' }}> {props.pr} </Typography> </Box> ) }) return ( <> <Grid container direction="row" pt={10} pl={1} pr={1} pb={1}> <Grid item xs={12}> <Typography variant="h2" sx={{textAlign:'center'}}> TITLE </Typography> </Grid> <Grid item xs={6}> <List aria-label="main list element"> <ListItemButton selected={selectedItemList === 0} onClick={ (e) => handleSelectedList(e, 0)}> <ListItemIcon> <InBoxIcon /> </ListItemIcon> <ListItemText primary="Inbox"/> </ListItemButton> <ListItemButton selected={selectedItemList === 1} onClick={ (e) => handleSelectedList(e, 1)}> <ListItemIcon> <DraftsRounded /> </ListItemIcon> <ListItemText primary="Drafts"/> </ListItemButton> </List> </Grid> <Grid item xs={6}> { selectedDivList ? <Fade in={selectedElemList} timeout={600}> <Compc {...selectedDivList} /> </Fade> : '' } </Grid> </Grid> </> ) }; export default MainContent;
关键修改点:
- 点击新列表项时,先将
selectedElemList设为false,让Fade组件进入隐藏状态 - 通过
setTimeout延迟50ms再更新选中项、内容并将selectedElemList设为true,确保组件有足够时间响应状态变化,触发完整淡入动画 - 优化了当前选中项的取消逻辑,状态切换更清晰
内容的提问来源于stack exchange,提问作者Lukas
相关产品推荐
相关产品推荐

