'How to work with conditional dynamically import in react
I'm trying to make a component which is receiving in the props a string[], iterating over every string, capitalize the string then dynamically import a module of jsx elements, the dependency and directory being "react-icons/si", at the resolve I'm successfully accessing the correct icon. I'm hitting a wall at trying to make that functional component into a proper JSX.Element, because I didn't import using destructuring.
Though Iknow go for the easy route -and probably the best- to just import every icon, I would appreciate any help with an ideia of how to do it and even if is possible.
The dependency of icons I'm working with is react-icons
export const TechIcons = ({techs}: TechIconsProps) => {
function capitalize(word: string):string {
const lowerCase = word.toLowerCase()
return word.charAt(0).toUpperCase() + lowerCase.slice(1)
}
let listOfTechs = [];
for(let i = 0; i < techs.length; i++) {
const tech = techs[i]
const techFormated = `Si${capitalize(tech)}`
import("react-icons/si")
.then((iconsTech) => {
console.log(iconsTech[techFormated]
})
.catch((err: Error) => {
console.log(err)
})
}
return (<>{listOfTechs.join('')}</>)
}
One example of that console.log, which is succesfully accessing the jsx element, but I'm unable to make it rendering.
f SiNodedotjs(props) {
return GenIcon({ "tag": "svg", "attr": { "role": "img", "viewBox": "0 0 24 24" }, "child": [{ "tag": "title", "attr": {}, "child": [] }, { "tag": "path", "attr": { "d": "M11.99…
Solution 1:[1]
It looks like react-icons/si is setup for named exports like:
import { IconName } from "react-icons/si";
You cannot dynamically import named exports. You may only dynamically import entire modules. This is because the import('path/here') function does not additionally take a name, only a path.
So dynamically importing any subset of named exports is not possible. You must dynamically import the entire module.
So that means you gain no value from a dynamic import. May as well import the whole library statically, and then pull icons from it dynamically. It also, sadly, means that since the bundler can't know what icons you intend to use at runtime, then it must bundle them all which could lead to a lot of extra icons in your bundle that never get used.
Import all the icons like this:
import * as SI from "react-icons/si"
Now SI has every named export as properties.
Now it seems you want to use a lowercased non-Si prefixed version of the name. So we need a type that gets all the icons available, and creates a union of those names.
type IconNames = {
[K in keyof typeof SI]: K extends `Si${infer U}` ? Lowercase<U> : never
}[keyof typeof SI]
// type IconNames = "1001tracklists" | "1password" | "3m" | "42" | "4d" | "500px" | "abbrobotstudio" | "abbvie" | "abletonlive" | "aboutdotme" | "abstract" | "academia" | "accenture" | "acclaim" | ... 2009 more ... | "zyte"
This type maps over all the icon names and infers the part of the name after Si and then makes it lowercase.
(Note: this capitalization strategy will not work for any of the icons that start with numbers, like 1Password or 500Px. 1password becomes 1password instead of the expected 1Password. I would probably just skip trying to change the icon name case, but that's your call.)
Now we can declare props like this:
interface TechIconProps {
techs: IconNames[]
}
And the component like this:
function TechIcons({techs}: TechIconProps) {
const techsFormatted = techs.map(tech => `Si${capitalize(tech)}`) as (keyof typeof SI)[]
return <>{
techsFormatted.map((icon, i) => {
const Icon = SI[icon]
return <Icon key={i} />
})
}</>
}
This even gives you autocomplete:
Note first that a React component cannot render asynchronously. It must return JSX immediately. So your import().then() can't make it into the render unless it's saved in sate or something. But since we import the icon set statically now, this isn't a problem anymore.
Note second the const Icon = SI[icon]. React doesn't consider <SI[icon] /> to be valid syntax so we stash that icon component to a local variable that makes it easy to render.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |

