【问题标题】:How can you instantiate a .gif file in a React app?如何在 React 应用程序中实例化 .gif 文件?
【发布时间】:2021-10-25 07:15:16
【问题描述】:

我有一个 React 应用程序,它可以做 3 件事;显示数组中的元素,在按钮按下时添加元素,在按钮按下时移除元素。

在我的图像内部,我正在显示我的本地 .gif 文件。我的 .gif 文件是单个动画 .gif,我关闭了无限循环,因为我希望 .gif 生成然后保持静态。

当我向数组中添加第二个 .gif 元素时出现错误。只有第一个元素显示其动画,其余元素显示 .gif 中的最后一张幻灯片。

我相信,如果我设法实例化元素,我或许能够解决我的问题,但我不确定我将如何去做。

这是我的代码的摘录::

function App(){
    const [numbValue, numbUpdate] = useState(0);
    const [starsValue, starsUpdate] = useState(null);
    
    function DisplayGIF(numbToDisp){
      let value=[];
      for(let i=0;i<numbToDisp;i++){
        value.push(<img className="icon" src={process.env.PUBLIC_URL + "/once-star-filled.gif"} alt="animated star"/>)
      }
      starsUpdate(<>{value.map(element=>{return element;})}</>);
    }

    function Add(){
      numbUpdate(numbValue+1);
      DisplayGIF(numbValue+1);
    }

    function Sub(){
      numbUpdate(numbValue-1);
      DisplayGIF(numbValue-1);
    }

    return(<>
      <p onClick={Add}>+</p>
      {starsValue}
      <p onClick={Sub}>-</p>
    </>);
  }

输出:: 首先添加 :: 显示 1 个动画直到结束的图像 连续添加::显示动画中显示最后一帧的x张图片

【问题讨论】:

  • 我已经更新了我的答案。现在,您只能获取一次图像。此解决方案对 cors 和最大 gif 大小有一些限制。

标签: javascript reactjs


【解决方案1】:

请试试这个。

function App() {
  const [stars, setStars] = useState(0);

  return (
    <React.Fragment>
      <p onClick={() => setStars((s) => s + 1)}>+</p>
      {new Array(stars).fill().map((s, ind) => {
        return <Star key={ind}></Star>;
      })}
      <p onClick={() => setStars((s) => (s === 0 ? 0 : s - 1))}>-</p>
    </React.Fragment>
  );
}

export function Star(props) {
  const [id] = useState(Math.random()); // Generate unique id for this item
  return (
    <img
      className="icon"
      src={`${process.env.PUBLIC_URL}/once-star-filled.gif?id=${id}`}
      alt="animated star"
    />
  );
}

我修复了一些符号错误,比如函数名应该以小写字母开头。 此外,您可以只使用一种状态来存储和渲染星星 gif。 此外,最好创建另一个 React 函数元素 &lt;Star /&gt;。这样你以后可以重用这个 gif,并添加一些道具,例如不同的alter textsrc attribute 和等。

[更新 1]

我不同意@Karl 的评论,他的解决方案有一个重大缺陷:当src 使用ind 形成时,元素只会被动画一次(例如:使用ind=2 删除元素并再次添加带有ind=2 的元素给我们一个静态图像)。

所以我决定用一个我不会在生产中使用的选项来补充我的答案,但它很有趣并且解决了 OP 的问题。

什么是新的解决方案?我们通过fetch获取图像,将其转换为dataUrl,删除metadata表示的第一部分,并将其传递给Star元素以作为src道具进行渲染。 每个元素都添加了带有自己Id的元信息,这不会影响文件本身,但浏览器会将图片视为新图片。因此,每次出现在页面上时都会启动动画。

import React, { useState, useRef } from "react";

import "./App.css";

function App() {
  const [stars, setStars] = useState(0);
  const [data, setData] = useState(null);

  const ref = useRef(null);

  React.useEffect(() => {
    fetch("./ezgif-2-110436c6c12b.gif")
      .then((res) => res.blob())
      .then(async (text) => {
        const reader = new FileReader();
        reader.onload = (ev) => {
          setData(
            ev.currentTarget.result.replace("data:image/gif;base64", "")
          );
        };
        reader.readAsDataURL(text);
      });
  }, []);

  return (
    <React.Fragment>
      <p onClick={() => setStars((s) => s + 1)}>+</p>
      {data &&
        new Array(stars).fill().map((s, ind) => {
          return <Star src={data} key={ind}></Star>;
        })}
      <p onClick={() => setStars((s) => (s === 0 ? 0 : s - 1))}>-</p>
    </React.Fragment>
  );
}

/**
 *
 * @param {{src: string}} props
 * @returns
 */
export function Star(props) {
  const [id] = useState(Math.random());

  return (
    <img
      className="icon"
      src={`data:image/gif;base64;${id}` + props.src}
      alt="animated star"
    />
  );
}

export default App;

【讨论】:

  • 我很感激这次尝试,不幸的是,当我尝试这个时没有任何改变。这不是一个有效的答案。
  • @Karl 我已经更新了答案,请在 url 查询中添加 id。
  • 解决方案似乎确实添加了一个 id,正如我在这个类似的问题“stackoverflow.com/questions/19831319/…”中发现的那样,在这个小评论中值得注意的是,你永远不应该随意为 id 分配随机数,因为它们是随机的,可能会有多个,这可能会造成灾难性的问题。不幸的是,您和其他论坛帖子的回答者都造成了一个可能的问题。我会正确回答我的问题并在那里更详细地解决您的问题。
猜你喜欢
  • 1970-01-01
  • 2016-11-05
  • 2019-01-01
  • 2022-11-20
  • 1970-01-01
  • 2021-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多