简体   繁体   中英

React: Import svg as component dynamically

In my application I got 8 svg files which I want to import dynamically. I have tried the following:

First I created a Floor component that has one name prop. This is the name of the floor that the user wants to see. In my dynamic import, the path to the svg is specified but it always seems to return undefined.

I know the path to the svg is correct because if I fill in a wrong path, React complains it can't find the svg file.

import React, { useEffect, useState } from "react";

const Floor = ({ name }) => {

  const [floor, setFloor] = useState(null);

  useEffect(() => {

    /*
    This is where it goes wrong. If I log the result It shows 'undefined'.
    */

    import(`./floors/${name}.svg`)
      .then((module) => {
        setFloor(module);
      })
      .catch((error) => {
        console.error(`Icon with name: ${name} not found!`);
      });
  }, [name]);

  const renderFloor = () => {
    if (!floor) return null;

    const Floor = floor.ReactComponent;

    return <Floor />;
  };

  return <>{renderFloor()}</>;
}

export default Floor;

And this is how I import the Floor

import Floor from './Floor'

const Floorplan = () => {

  return (
    <Floor name="floor-4" />
  )
}

export default Floorplan;

I have found something similar but I still have the same error 'undefined'

These are the errors Im getting.

And if I log the dynamic import response:

I believe the problem is webpack cannot determine what your ${name}.svg will look like in runtime and does not include them inside any chunk. To force this behavior you should include somemagic comments inside your dynamic import. Something like:

  ...
  useEffect(() => {
    import(
      /* webpackInclude: /\.svg$/ */
      /* webpackChunkName: "svg-imgs-chunk" */
      /* webpackMode: "lazy" */
      `./floors/${name}.svg`)
      .then((module) => {
        setFloor(module);
      })
  ...

The below worked for me. I had my svgs in a folder inside src , and was using the companyName prop for the svg filename. I also used a regex to format companyName to all lower case and no space (like the svg filenames)

  const [iconUrl, setIconUrl] = useState(false)

  const { companyName } = job.companyByCompany

  useEffect(() => {
    iconFetch(companyName.toLowerCase().replace(/\s+/g, ''))
  }, [companyName])

  const iconFetch = async (iconName) => {
    await import(`../assets/logos/${iconName}.svg`)
    .then(data => setIconUrl(data.default))
    .catch(err => console.log(err))
  }

I could then access the svg's via the src attribute in an img tag.

<img src={iconUrl} alt={`${companyName} svg`}/>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM