如何在 React 中导入 SVG 图标

How to Import SVG icons in React

我想在应用程序中导入太多 SVG 图标,并且每个图标都需要通过 css 自定义颜色,哪种导入方式最简单? 导入到 <img/> 标签将不支持通过 css 填充更改颜色。 为每个图标创建一个 .js 组件对于 250 多个图标来说太难了。 另一个选择是什么?请帮忙

import IconArrow from "./Arrow.svg";
import Circlearrowdownright from "./Arrow.js";

<img className="ico" src={IconArrow} />
<i className="ico"><Circlearrowdownright /></i>

https://codesandbox.io/s/svg-icon-3z0qu6

您可以动态导入 SVG 并即时渲染 (CodeSandbox)。无需为每个 SVG 文件创建单独的 .js 组件。

hook

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 };
}

Icon 使用钩子的组件

/**
 * Simple wrapper for dynamic SVG import hook. You can implement your own wrapper,
 * or even use the hook directly in your components.
 */
export const Icon = ({ name, onCompleted, onError, ...rest }) => {
  const { error, loading, SvgIcon } = useDynamicSVGImport(name, {
    onCompleted,
    onError
  });
  if (error) {
    return error.message;
  }
  if (loading) {
    return "Loading...";
  }
  if (SvgIcon) {
    return <SvgIcon {...rest} />;
  }
  return null;
};

用法

return (
    <>
      <Icon
        name="Arrow"
        fill="gray"
        width="100"
        onCompleted={handleOnCompleted}
        onError={handleIconError}
      />
      <Icon
        name="delete"
        fill="gray"
        width="50"
        onCompleted={handleOnCompleted}
        onError={handleIconError}
      />
    </>
  );

React 与本机 Web 组件配合得很好。只有当您想使用事件与它们交互或传递数据时,React(仍然)无法支持标准:https://custom-elements-everywhere.com/

  • 创建一个 <svg-icon> 标签仅需几行代码。
  • 添加了 replaceWith 属性,因此您加载的 <svg> 会替换 <svg-icon>,从而更易于使用全局 CSS.
  • 添加了一个 shadowRoot 属性 将任何内容 移动到 shadowDOM

customElements.define("svg-icon", class extends HTMLElement {
  async connectedCallback(
    src = this.getAttribute("src"),
    shadowRoot = this.shadowRoot || this.attachShadow({mode:"open"})
  ) {
    shadowRoot.innerHTML = await (await fetch(src)).text()
    shadowRoot.append(...this.querySelectorAll("[shadowRoot]"))
    this.hasAttribute("replaceWith") && this.replaceWith(...shadowRoot.childNodes)
  }
});
body {
  display: grid;
  grid: 1fr/1fr 5fr;
}

path {
  stroke: green;
  stroke-width: .2;
  fill: red;
}
<svg-icon replaceWith src="https://svg-cdn.github.io/bi-arrows.svg"></svg-icon>
<svg-icon src="https://svg-cdn.github.io/simple-worldmap.svg">
  <style shadowRoot>
    path {
      fill: orange
    }
  </style>
</svg-icon>

您可以直接将其作为 React 组件导入使用:

import { ReactComponent as ExampleIcon} from './icons/ExampleIcon.svg';

<ExampleIcon className="css-class"/>