Избегайте дублирования определений фильтров при рендеринге SVG с помощью React - PullRequest
1 голос
/ 14 октября 2019

Я использую React для рендеринга некоторых элементов SVG, которые включают фильтры. Вот упрощенный пример:

function ShadowCircle() {
  return (
    <g>
      <defs>
        <filter id="dropShadow" x="-20%" y="-20%" width="200%" height="200%">
          <feOffset result="offOut" in="SourceAlpha" dx="1" dy="1" />
          <feGaussianBlur result="blurOut" in="offOut" stdDeviation="1" />
          <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
        </filter>
      </defs>
      <circle r="4" cx="50" cy="50" fill="blue" filter="url(#dropShadow)" />
    </g>
  );
}

function App() {
  return <svg width="100" height="100">
    <ShadowCircle />
  </svg>
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Это прекрасно работает, если я только отображаю только один экземпляр моего <ShadowCircle />, в противном случае я получаю дублирующие фильтры (и дублирующие идентификаторы) вDOM.

В идеале я хотел бы иметь возможность:

  • Убедитесь, что при визуализации одного или нескольких теневых кругов отображается только один фильтр
  • Удалите фильтркогда он не используется

Я пробовал индивидуальный подход, используя createPortal и useEffect hook, но я столкнулся с парой проблем:

  • ItНевозможно отобразить SVG Elements, не заключая их в теги <svg>, поэтому портал должен быть <div>, и все мои фильтры заканчиваются отдельными <svg> документами.
  • Вызов getElementById внутриuseEffect, чтобы проверить, был ли фильтр уже на странице, оказался ненадежным, особенно когда на страницу одновременно выводятся несколько элементов.

Как можно отобразить один фильтр при необходимости(одним или несколькими компонентами) и remпосле этого?

...