简体   繁体   中英

How can I modify the tagName of an imported 3rd party react component?

I'm using babel-plugin-inline-react-svg to import SVGs and use them as react components. The problem is i need to embed these SVGs inside another SVG. I'd like to convert the root tag svg to symbol . When I import the SVG as is, what results is nested SVG tags. Which technically works, but not without many quirks for my target implementation (phantomjs). I'd rather use use xlink:href , but i'd need to convert the root element generated by the 3rd party lib to have tag name symbol

Here's some fictitious usage

import Flag from 'images/icons/flag.svg'

export default () => {
  return (
     <svg>
       <Flag/>
       <text>Foo</text>
     </svg>
   )
}

What this renders is

<svg>
    <svg>
      <!-- contents of svg -->
    </svg>
    <text>Foo</text>
</svg>

What i'd like to be able to do is

import Flag from 'images/icons/flag.svg'

export default () => {
  return (
     <svg>
       <defs>
          <Flag as="symbol" id="flag"/>
       </defs>
       <use xlinkHref="#flag"/>
       <text>Foo</text>
     </svg>
   )
}

It must be a really common use-case to have to change the tagName of the root element of a 3rd party library. If nothing, but just adding aria tags, using semantic element names, so on..

How can I change the tagName of a react component i have no control over?

I ended up using a Higher Order Component to intercept the ReactDOMElement coming from the 3rd party lib. I switched the type of the element before it renders. Inspired heavily by https://github.com/pwmckenna/react-transform-style/blob/master/src/index.js

const TransformTag = (Component, tagName) => {
  const ModifiedComponent = Component
  const isFn = (typeof(Component) === 'function')
  const render = isFn ? ModifiedComponent : ModifiedComponent.render
  const modifiedRender = function() {
    const {
      props,
      ...renderedRest
    } = render.apply(this, arguments)

    renderedRest.type = tagName // this is the magic
    return {
      props,
      ...renderedRest
    }
  }
  if (isFn) {
    return modifiedRender
  } else {
    ModifiedComponent.prototype.render = modifiedRender
    return ModifiedComponent
  }
}

// usage 

export default SvgQuote = () => { 
   return (
      <svg>
         <defs> 
            { TransformTag(Bill, 'symbol') }
         </defs>
      </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