Incrustar SVG en ReactJS

127

¿Es posible incrustar el marcado SVG en un componente ReactJS?

render: function() {
  return (
    <span>
      <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmln ...
    </span>
  );
}

Resultados en el error:

Los atributos del espacio de nombres no son compatibles. ReactJSX no es XML.

¿Cuál es la forma más ligera de hacer esto? Usar algo como React ART es una exageración para lo que estoy tratando de hacer.

nicholas
fuente
1
¿Puedes crear un jsbin? Puede ser tan simple como cambiar su etiqueta SVG de apertura a solo <svg id="Layer_1">(o incluso mejor, sin la identificación). Editar: he aquí un ejemplo: jsbin.com/nifemuwi/2/edit?js,output
bandido del
@FakeRainBrigand ¡Gracias! Fue así de simple en este caso. Sin embargo, mira la respuesta de Ben. Es bueno saber que puede evitar el análisis jsx cuando lo necesita.
Nicholas

Respuestas:

178

Actualizar 2016-05-27

A partir de React v15, el soporte para SVG en React es (cercano a?) 100% de paridad con el soporte actual del navegador para SVG ( fuente ). Solo necesita aplicar algunas transformaciones de sintaxis para que sea compatible con JSX, como ya tiene que hacer para HTML ( classclassName, style="color: purple"style={{color: 'purple'}}). Para cualquier atributo de espacio de nombres (separados por dos puntos), por ejemplo xlink:href, elimine :y capitalice la segunda parte del atributo, por ejemplo xlinkHref. He aquí un ejemplo de un SVG con <defs>, <use>y estilos en línea:

function SvgWithXlink (props) {
    return (
        <svg
            width="100%"
            height="100%"
            xmlns="http://www.w3.org/2000/svg"
            xmlnsXlink="http://www.w3.org/1999/xlink"
        >
            <style>
                { `.classA { fill:${props.fill} }` }
            </style>
            <defs>
                <g id="Port">
                    <circle style={{fill:'inherit'}} r="10"/>
                </g>
            </defs>

            <text y="15">black</text>
            <use x="70" y="10" xlinkHref="#Port" />
            <text y="35">{ props.fill }</text>
            <use x="70" y="30" xlinkHref="#Port" className="classA"/>
            <text y="55">blue</text>
            <use x="0" y="50" xlinkHref="#Port" style={{fill:'blue'}}/>
        </svg>
    );
}

Demostración de codepen de trabajo

Para obtener más detalles sobre soporte específico, consulte la lista de documentos de atributos SVG admitidos . Y aquí está el problema (ahora cerrado) de GitHub que rastreó el soporte para los atributos SVG de espacios de nombres.


Respuesta anterior

Puede hacer una incrustación SVG simple sin tener que usar dangerouslySetInnerHTMLsimplemente quitando los atributos del espacio de nombres. Por ejemplo, esto funciona:

        render: function() {
            return (
                <svg viewBox="0 0 120 120">
                    <circle cx="60" cy="60" r="50"/>
                </svg>
            );
        }

En ese momento, puede pensar en agregar accesorios como fill, o cualquier otra cosa que pueda ser útil para configurar.

Andrew Patton
fuente
@ChinonsoChukwuogor ¡Gran pregunta! No sé, nunca he usado React Native. ¿Lo intentaste?
Andrew Patton
@AndrewPatton Los nombres de clase de CSS múltiple con el tick char no funcionan: ' .class1, .class2{fill: #005baa;}' ¿Cómo puedo solucionarlo?
HelloWorld
@HelloWorld ¿Puedes darme un ejemplo donde no funciona? Acabo de bifurcar mi demo original para agregar classBy funcionó: codepen.io/acusti/pen/BVJzNg
Andrew Patton
Gracias, a partir de esto, logré importar un archivo svg desde un componente React sin ningún cargador, acabo de eliminar `` `xmlns: osb =" openswatchbook.org/uri/2009/osb "` `` de la etiqueta svg, dejando solo las xlmns. Aparentemente, se trata de analizar etiquetas. Por si acaso, he seguido estos pasos, así: blog.logrocket.com/how-to-use-svgs-in-react
Financiador
56

Si solo tiene una cadena de svg estática que desea incluir, puede usar dangerouslySetInnerHTML:

render: function() {
    return <span dangerouslySetInnerHTML={{__html: "<svg>...</svg>"}} />;
}

y React incluirá el marcado directamente sin procesarlo en absoluto.

Sophie Alpert
fuente
3
Estoy controlando algunas rutas dentro de SVG usando React, pero React no parece admitir los elementos de filtro. ¿Hay alguna manera de apoyar esto? Parece que peligrosamente SetInnerHTML no funcionará porque no puedo poner un espacio dentro de un SVG y no puedo usar eso para establecer el atributo de filtro en las rutas. No creo que haya una manera de crear elementos React como de costumbre, pero ¿deben pasar todos los atributos textualmente a los elementos DOM?
Andy
Como 2019, parece que puedes usar dangerouslySetInnerHTML, pero aún así no pude hacer que el filtro de sombra funcione en Chrome usando dangerouslySetInnerHTML, pero está funcionando en Firefox.
Shnd
31

Según un desarrollador de react , no necesita el espacio de nombres xmlns. Si necesita el atributo xlink:href, puede usar xlinkHref de react 0.14

Ejemplo

Icon = (props) => {
  return <svg className="icon">
    <use xlinkHref={ '#' + props.name }></use>
  </svg>;
}
lastid
fuente
12

Si desea cargarlo desde un archivo, puede intentar usar React-inlinesvg , que es bastante simple y directo.

import SVG from 'react-inlinesvg';

<SVG
  src="/path/to/myfile.svg"
  preloader={<Loader />}
  onLoad={(src) => {
    myOnLoadHandler(src);
  }}
>
  Here's some optional content for browsers that don't support XHR or inline
  SVGs. You can use other React components here too. Here, I'll show you.
  <img src="/path/to/myfile.png" />
</SVG>
Youkko
fuente