Reputation: 1584
I have a scenario in which I want to dynamically tell a child component which image to show, based on an required image passed down by the parent, as such:
Parent:
function Social() {
return (
<SocialBar>
{
SocialMedias.map((media) =>{
return <SocialApp
key={uuidv4()}
link={media.link}
social={require(media.icon)}
/>
})
}
</SocialBar>
);
}
Child
function SocialApp(props) {
return (
<Social href={props.link} target="_blank">
<CustomSizedImage src={props.social.default} />
</Social>
);
}
Which seems pretty straight forward, right? However, this causes the error below:
I've seen some posts say that this is caused because the path is not absolute. However, I tested with absolute paths and it still doesn't work. The funny thing is, when I changed the parent code to the below for testing, it worked.
New parent code:
function Social() {
const img = require("../assets/icons/social-media/instagram.svg");
return (
<SocialBar>
{
SocialMedias.map((media) =>{
return <SocialApp
key={uuidv4()}
link={media.link}
social={img}
/>
})
}
</SocialBar>
);
}
export default Social;
The result:
OBS: I tested with EVERY image that this code will possibly load. Is not an image/image path related issue.
What is expected of all this is to dynamically load icons for social media with the correct URLs, etc. What I do not understand is: why does it work when I require the image outside the return?. I know I could make this work by iterating media
object outside of return and use the resulting array with the map index, but that doesn't seem clean. Why does it have this behavior? Is there a way to make it work inside the map?
Upvotes: 1
Views: 57
Reputation: 8718
Your last code snippet works because the path is known at compile time.
I assume you use a bundler like Webpack or similar. When they compile your project, they check all imports (including require calls)
, use that to calculate the dependency tree, and finally bundle all required files together. For images, that includes "compiling it into a module" which just returns the path to the image.
Usually that also involves replacing paths with module identifiers. E.g. if you ever looked at the built Webpack code, you'll notice that it doesn't use e.g. require('./module')
but __webpack_require.c(5)
or something similar. It gave the module './module'
the unique ID 5
in the bundled code.
With your earlier code snippets, when using a dynamic require with a non-constant string, Webpack just doesn't know that you'll request that image. Nor would it know the new unique ID to use for that.
The easiest solution is to import your images somewhere and use those references dynamically:
// images.ts
export IconA from './media/icon-a.svg';
export IconB from './media/icon-b.svg';
// somewhere else
import { IconA, IconB } from './images';
const iconPath = someCondition ? IconA : IconB;
Of course, you don't have to use the import/require mechanic. You can simply have your icon path be an actual path, relative to your public/
folder.
Upvotes: 1