React动态加载图片

5

我创建了一个渲染图片的组件。

这是该组件。

import React, { lazy, Suspense } from "react";

const Icon = (props) => {
    const { src } = props;

    return (
        <img src={src}  />
    );
};

export default Icon;

然后我像这样使用它

import ExampleIcon from "./../images/icons/example.png";
...
<Icon src={ExampleIcon} />

有没有更有效的方法来加载图标?直接 "加载" example.png 并将其用作源可以吗?尝试将其更改为:

const Icon = (props) => {
    const src = lazy(() => import("./../images/icons/" + props.src + ".png"));
    return (
        <Suspense fallback={<p>loading...</p>}><img src={src} /></Suspense>
    );
};

看起来它不起作用。还有什么其他的想法吗?谢谢!


1
我删除了我的回答,因为我查看了文档,发现我的解决方法不可行。有两种方法可以进行懒加载:你可以懒加载组件(而不是img标签的源),或者添加loading="lazy"属性来使用本地的图像懒加载。我不会将此作为答案留下,因为我不确定你想要的方向,并且实际上还没有测试这个解决方案。 - technicallynick
loading="lazy"是仅在视口中时才加载图像。我想要实现的是动态加载图像,这是不同的事情。但是谢谢。 - handsome
你可以根据你的构建工具内联加载SVG。对于许多这样的工具,这个是要做的事情。如果不行,那个链接也包含一些相对手动的替代方法。 - loremdipso
通常情况下使用<img src={src}/>处理事物的效率不够高,具体哪一点不够高效呢?因为它只有在渲染img时才会真正运行获取图像的方法。 - Zachary Haber
“动态加载图像”这个说法非常模糊。你想要做什么?如果你想要懒加载图片,可以使用loading="lazy"来帮助你;如果你想要实现某种代码分割,那么就需要使用Lazy和Suspense。@technicallynick的评论也很有道理。如果你能解释一下你想要的最终结果,那会很有帮助。 - Sunil Chaudhary
2个回答

2
不行,因为 React.lazy() 必须在顶层且只能返回 React 组件。如果想要懒加载图片,可以在 effect 内部实现此功能:
function Icon = props => {
    const [image, setImage] = useState()

    useEffect(() => {
        import("./../images/icons/" + props.src + ".png").then(setImage)
    }, [props.src])


    return image ? <img src={image} /> : 'Loading...'
}

编辑:这里有一个小问题,就是Webpack无法找到要分割的文件,因为import函数中的字符串不是文字。你仍然可以使用fetch动态访问public目录中的文件。也许你根本不需要使用fetch,只需提供一个src链接,避免所有麻烦。

1
您可以采用这种方法: 使用JavaScript预加载图片
const img=new Image();
img.src=url;

如何使用钩子以及在线示例:

https://www.selbekk.io/blog/2019/05/how-to-write-a-progressive-image-loading-hook/

另一种方法只使用钩子:

https://codesandbox.io/s/magical-pine-419kz?file=/src/App.tsx

import React, { useEffect } from "react";
import "./styles.css";

const loadImg = (src: string): Promise<string> =>
  new Promise((resolve, reject) => {
    const img = new Image();
    img.src = src;
    img.onload = () => resolve(src);
    img.onerror = () => reject(new Error("could not load image"));
  });

export default function App() {
  const [src, setSrc] = React.useState("preloadimg");
  useEffect(() => {
    const load = async () => {
      await loadImg(
        "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8c/Chess_Large.JPG/800px-Chess_Large.JPG"
      ).then((src) => {
        setSrc(src);
      });
    }; // Execute the created function directly
    load();
  }, [src, setSrc]);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <img src={src} alt="example" />
    </div>
  );
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接