Как динамически импортировать SVG и сделать его встроенным - PullRequest
0 голосов
/ 21 апреля 2020

У меня есть функция, которая принимает некоторые аргументы и отображает SVG. Я хочу динамически импортировать этот svg на основе имени, переданного функции. Это выглядит следующим образом:

import React from 'react';

export default async ({name, size = 16, color = '#000'}) => {
  const Icon = await import(/* webpackMode: "eager" */ `./icons/${name}.svg`);
  return <Icon width={size} height={size} fill={color} />;
};

Согласно документации для динамического c импорта и комментария magi c "eager":

"Не генерирует лишний чанк. Все модули включены в текущий чанк, и никакие дополнительные сетевые запросы не делаются. Обещание все еще возвращается, но уже разрешено. В отличие от импорта c, модуль не выполняется до сделан вызов import (). "

Это то, к чему мой Icon разрешен:

> Module
default: "static/media/antenna.11b95602.svg"
__esModule: true
Symbol(Symbol.toStringTag): "Module"

Попытка отобразить его так, как пытается дать моя функция мне эта ошибка:

Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.

Я не понимаю, как использовать этот импортированный модуль, чтобы отобразить его как компонент, или это вообще возможно?

Ответы [ 2 ]

1 голос
/ 28 апреля 2020

Наконец-то разобрался, как это сделать. Вы можете использовать именованные экспорты ref и ReactComponent при импорте файла SVG. Обратите внимание, что это должно быть ref, как я тестировал, используя состояние для хранения импортированного SVG ReactComponent, и он не работает.

Пример Dynami c Компонент SVG:

const Icon = ({ name, ...rest }) => {
  const ImportedIconRef = React.useRef(null);
  const [loading, setLoading] = React.useState(false);

  React.useEffect(() => {
    setLoading(true);
    const importIcon = async () => {
      try {
        ImportedIconRef.current = (await import(`./${name}.svg`)).ReactComponent;
      } catch (err) {
        // Your own error handling logic, throwing error for the sake of
        // simplicity
        throw err;
      } finally {
        setLoading(false);
      }
    };
    importIcon();
  }, [name]);

  if (!loading && ImportedIconRef.current) {
    const { current: ImportedIcon } = ImportedIconRef;
    return <ImportedIcon {...rest} />;
  }

  return null;
};

Вы можете также реализовать свои собственные логики обработки ошибок c. Может быть, ошибка или что-то в этом роде.

Рабочая демонстрация CodeSandbox:

Edit react-dynamic-svg-import

1 голос
/ 21 апреля 2020

Ваши функции рендеринга (для компонентов класса) и компоненты функций не должны быть асинхронными c (потому что они должны возвращать DOMNode или null - в вашем случае они возвращают Promise). Вместо этого вы можете визуализировать их обычным способом, после чего импортировать значок и использовать его при следующем рендеринге. Попробуйте следующее:

const Test = () => {
  let [icon, setIcon] = useState('');

  useEffect(async () => {
    let importedIcon = await import('your_path');
    setIcon(importedIcon.default);
  }, []);

  return <img alt='' src={ icon }/>;
};
...