我试图在React中使用钩子重新启动GIF动画



我发现了类似的问题,我试图修改答案,我特别关注这个问题。这里的目标是让GIF在每次显示该组件时重新启动。我的示例代码已经经过了一两次迭代,这就是它现在的位置。

import {useState, useEffect} from "react"
import Footer from "../components/Footer";
import NavMenu from '../components/NavMenu'
import {Box, Typography} from '@mui/material'
import backgroundImage from '../assets/images/world-bg.png'
import Logo from '../assets/images/chr-logo-white@2x.png'
import landscape from '../assets/gifs/why-we-exist_1test.gif'
import { Gif } from "@mui/icons-material";

const Exist = () => {
const [gif, setGif] =useState('')
const reloadGif = () => {
setGif('')
setTimeout(() => {
setGif(landscape)
}, 0)
}
useEffect(() => {
reloadGif()
return () => {
setGif('')
}
},[]
)
const styles ={
introContainer:{
height: '100%',
width: '100vw',
backgroundImage: `url(${backgroundImage})`,
display: 'flex',
flexDirection: 'column',
alignContent: 'center',
color:'white',
textAlign:'center',
justifyContent: 'center',
alignContent:'center',
flexShrink:0
}
}
return (
<Box sx = {styles.introContainer}>
<NavMenu />
<Box >
{gif !== '' && <img src={gif} alt="Logo"></img>}
</Box>
<Footer logo={false} back={'intro'} next={"home"}/>
</Box>
)
}
export default Exist;

我希望我的useEffect会清除图像src,然后设置它再次强制重新渲染。我看到的问题是,空依赖数组不会触发重新渲染,但没有它,我得到不断的重新渲染,但GIF仍然只播放一次。

这里的问题是最有可能,你没有一个明确的方式再触发器使用效果Gif重载。

对此有几种解决方案,但这取决于您如何实现显示和不显示组件的逻辑。

正如您已经实现的那样,每当组件被放到屏幕上时,就会触发带有空依赖数组的useEffect。

作为解决方案,您需要检查您当前如何将您的组件与gif呈现到屏幕上。当你想播放gif时,你必须确保它是新添加到DOM的。

作为旁注:在useEffect中不需要返回函数。

const ParentComponent = () => {
const [showChildComponent, setShowChildComponent] = useState(true)

return (
<>
<button onClick={() => {setShowChildComponent(!showChildComponent)}}>
Click me to show or hide the child component
</button>
{ showChildComponent && <ChildComponent /> }
</>
)
}
const ChildComponent = () => {
const [gif, setGif] =useState('')
const reloadGif = () => {
setGif('')
setTimeout(() => {
setGif(landscape)
}, 0)
}
useEffect(() => {
reloadGif()
},[]
)
return (<img src={gif} alt="Logo"></img>) 
}

你也可以在prop/state的帮助下重新触发useEffect。下面的useEffect将在每次你的showGif状态改变时被重新触发,你可以在你想播放你的gif时设置。

const [retriggerGif, setRetriggerGif] = useState(true)
useEffect(() => {
reloadGif()
},[retriggerGif]
)

如果你不能挂载/卸载你的组件

在你的评论中,你提到你使用了一个基于哈希的路由器,并且只把你的组件包装在RouterLink中。

在这种情况下,你可以让你的useEffect依赖于你的路由器的哈希值,并总是重新运行哈希值的变化:

这当然取决于你使用的路由器,但总有一种方法可以获得当前活动的路径和哈希值。

在react-router中,你可以像这样通过useHistory()钩子获得history对象:

const history = useHistory() 
useEffect(() => { 
// check that you are at the correct hash 
if(history.hash === 'header') { 
reloadGif() 
} 
}, [history]) 

以@Carolin的回答为起点。我想出了一个解决方案,虽然感觉有点粗糙,但很有效。

import {useEffect} from "react"
import Footer from "../components/Footer";
import NavMenu from '../components/NavMenu'
import {Box} from '@mui/material'
import backgroundImage from '../assets/images/world-bg.png'
import landscape from '../assets/gifs/why-we-exist_1test.gif'


const Exist = ({viewCount, handleView}) => {

useEffect(() => {
return () => {
return handleView(viewCount + 1)
}
},[])
const styles ={
introContainer:{
height: '100%',
width: '100vw',
backgroundImage: `url(${backgroundImage})`,
display: 'flex',
flexDirection: 'column',
alignContent: 'center',
color:'white',
textAlign:'center',
justifyContent: 'center',
alignContent:'center',
flexShrink:0
}
}
return (
<Box sx = {styles.introContainer}>
<NavMenu />
<Box >
{viewCount %2 === 0 && <img src={landscape + "?=" + Date.now()} alt="Logo"></img>}
{viewCount %2 !== 0 && <img src={landscape + "?=" + Date.now()} alt="Logo"></img>}
</Box>
<Footer logo={false} back={'intro'} next={"home"}/>
</Box>
)
}
export default Exist;

其中viewCount和handleView是来自父组件的const [count, setCount]=useState(0)道具