您可以使用ref
和ReactComponent
导入SVG文件时命名为出口。请注意,它必须是ref
为了它的工作。
以下示例使用需要版本v16.8
及更高版本的 React 钩子。
示例动态 SVG 导入挂钩:
function useDynamicSVGImport(name, options = {}) {
const ImportedIconRef = useRef();
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
const { onCompleted, onError } = options;
useEffect(() => {
setLoading(true);
const importIcon = async () => {
try {
ImportedIconRef.current = (
await import(`./${name}.svg`)
).ReactComponent;
if (onCompleted) {
onCompleted(name, ImportedIconRef.current);
}
} catch (err) {
if (onError) {
onError(err);
}
setError(err);
} finally {
setLoading(false);
}
};
importIcon();
}, [name, onCompleted, onError]);
return { error, loading, SvgIcon: ImportedIconRef.current };
}
typescript中的动态 SVG 导入钩子示例:
interface UseDynamicSVGImportOptions {
onCompleted?: (
name: string,
SvgIcon: React.FC<React.SVGProps<SVGSVGElement>> | undefined
) => void;
onError?: (err: Error) => void;
}
function useDynamicSVGImport(
name: string,
options: UseDynamicSVGImportOptions = {}
) {
const ImportedIconRef = useRef<React.FC<React.SVGProps<SVGSVGElement>>>();
const [loading, setLoading] = useState(false);
const [error, setError] = useState<Error>();
const { onCompleted, onError } = options;
useEffect(() => {
setLoading(true);
const importIcon = async (): Promise<void> => {
try {
ImportedIconRef.current = (
await import(`./${name}.svg`)
).ReactComponent;
onCompleted?.(name, ImportedIconRef.current);
} catch (err) {
onError?.(err);
setError(err);
} finally {
setLoading(false);
}
};
importIcon();
}, [name, onCompleted, onError]);
return { error, loading, SvgIcon: ImportedIconRef.current };
}
对于那些谁是得到undefined
了ReactComponent
时,SVG动态进口的,这是由于一个错误,其中的WebPack插件添加ReactComponent
到以某种方式进口不会触发动态进口各SVG。
基于此解决方案,我们可以通过在动态 SVG 导入中强制使用相同的加载器来临时解决该问题。
唯一的区别是ReactComponent
现在是default
输出。
ImportedIconRef.current = (await import(`!!@svgr/webpack?-svgo,+titleProp,+ref!./${name}.svg`)).default;
另请注意,使用带有可变部分的动态导入时存在限制。这个 SO 答案详细解释了这个问题。
要解决此问题,您可以使动态导入路径更加明确。
例如,代替
// App.js
<Icon path="../../icons/icon.svg" />
// Icon.jsx
...
import(path);
...
你可以把它改成
// App.js
<Icon name="icon" />
// Icon.jsx
...
import(`../../icons/${name}.svg`);
...