I have an Articles component that shows a blog page with listed articles.
render() {
const articles = {
...this.state.articles
}
const article = Object.keys(articles).map(cur => {
return <Article
key={this.state.articles[cur].id}
imgName={this.state.articles[cur].thumb}
title={this.state.articles[cur].title}
meta={this.state.articles[cur].meta}
clicked={() => this.detailedHandler(this.state.articles[cur].id)}
detailed={this.state.articles[cur].detailed} />
});
As you can see I pass image name with props to Article component. I want then to display the appropriate image for each article.
How do I import an image in Article component based on the props I receive (props.imgName) from Articles component?
For anyone looking for a modern approach using async-await and custom react hooks, I found a pretty slick solution. Create a file called useImage.js
and paste the following code:
import { useEffect, useState } from 'react'
const useImage = (fileName) => {
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
const [image, setImage] = useState(null)
useEffect(() => {
const fetchImage = async () => {
try {
const response = await import(`../assets/img/${fileName}`) // change relative path to suit your needs
setImage(response.default)
} catch (err) {
setError(err)
} finally {
setLoading(false)
}
}
fetchImage()
}, [fileName])
return {
loading,
error,
image,
}
}
export default useImage
Then just import the custom hook into your image component, mine looks something like this:
import useImage from '../../hooks/useImage'
import Typography from './Typography' // simple plain-text react component
const Image = ({ fileName, alt, className, ...rest }) => {
const { loading, error, image } = useImage(fileName)
if (error) return <Typography>{alt}</Typography>
return (
<>
{loading ? (
<Typography>loading</Typography>
) : (
<img
className={`Image${
className
? className.padStart(className.length + 1)
: ''
}`}
src={image}
alt={alt}
{...rest}
/>
)}
</>
)
}
export default Image
The nice thing about this solution is that no matter where your component is in relation to your assets folder, the react hook is always in the same place, so the relative path stays the same.
I used context.
const images = require.context('../../../assets/img', true);
loadImage = imageName => (assets(`./${imageName}`).default);
<img src={loadImage("someimage.png")} alt="" />
I don't know if this is an optimal solution, but it works.
You can load images dynamically from the API response with dynamic imports
that is Stage 3 proposal as of now.
The resulting code should look something like:
loadImage = imageName => {
import(`./assets/${imageName}.jpg`).then(image => {
this.setState({
image
});
});
};
render() {
const { image } = this.state;
return (
<Fragment>
{image && <img src={image} alt="" />}
</Fragment>
);
}
View Codesandbox Demo
This feature is supported out of the box in create-react-app
, If using other systems, you can use the Babel plugin
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With