首页 > 解决方案 > 我正在尝试使用钩子在 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 仍然只播放一次。

标签: javascriptreactjsreact-hooksanimated-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>) 
}

您还可以在道具/状态的帮助下重新触发 useEffect。每当您的 showGif 状态发生变化时,都会重新触发以下 useEffect,您可以在想要播放 gif 时进行设置。

   const [retriggerGif, setRetriggerGif] = useState(true)

    useEffect(() => {
       reloadGif()
    },[retriggerGif]
    )

如果您无法安装/卸载您的组件

In the comments you mentioned you use a hash based router and only wrap your component in a RouterLink.

In this case you could make your useEffect depend on the hash of your router and always rerun of the hash changes:

This of course depends on what router you are using but there is always a way to get the currently active path and hash somehow.

In react-router you e.g. can get the history object through the useHistory() hook like this:

const history = useHistory() 

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

推荐阅读