Reputation: 2422
I created a component that renders images
this is the component.
import React, { lazy, Suspense } from "react";
const Icon = (props) => {
const { src } = props;
return (
<img src={src} />
);
};
export default Icon;
then I use it like this
import ExampleIcon from "./../images/icons/example.png";
...
<Icon src={ExampleIcon} />
is there a more efficient way to load the icons? and then just "load" example.png and use it as a source? tried to change it to:
const Icon = (props) => {
const src = lazy(() => import("./../images/icons/" + props.src + ".png"));
return (
<Suspense fallback={<p>loading...</p>}><img src={src} /></Suspense>
);
};
looks like it doesn´t work that way. any other ideas? thanks!
Upvotes: 5
Views: 6713
Reputation: 3806
You could apply this approach: Preloading images with JavaScript
const img=new Image();
img.src=url;
And how to do it with a hook with an online example:
https://www.selbekk.io/blog/2019/05/how-to-write-a-progressive-image-loading-hook/
Another approach just using hooks:
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>
);
}
Upvotes: 1
Reputation: 16294
No, you can't do this, since React.lazy()
must be at the top level and only return React components. To lazily load images you can do inside an 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...'
}
Edit: there's one little problem with this, namely, Webpack will not be able to figure out the file to code split since the string in the import
function is not a literal. You could still access files in the public
directory dynamically using fetch
instead. And perhaps you don't need fetch at all, just provide an url to src
and spare the whole hassle.
Upvotes: 2