Incorporando SVG ao ReactJS

127

É possível incorporar a marcação SVG em um componente ReactJS?

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

Resultados no erro:

Os atributos do espaço para nome não são suportados. ReactJSX não é XML.

Qual é a maneira mais leve de fazer isso? Usar algo como React ART é um exagero para o que estou tentando fazer.

nicholas
fonte
1
Você pode criar um jsbin? Pode ser tão simples quanto alterar sua tag SVG de abertura para apenas <svg id="Layer_1">(ou melhor ainda, sem o ID). Edit: aqui está um exemplo: jsbin.com/nifemuwi/2/edit?js,output
Brigand
@FakeRainBrigand Thanks! Era simples assim neste caso. Veja a resposta de Ben. É bom saber que você pode contornar a análise de jsx quando precisar.
Nicholas

Respostas:

178

Atualização 2016-05-27

A partir do React v15, o suporte ao SVG no React é (próximo a?) 100% de paridade com o suporte atual do navegador ao SVG ( origem ). Você só precisa aplicar algumas transformações de sintaxe para torná-lo compatível com JSX, como você já precisa fazer para HTML ( classclassName, style="color: purple"style={{color: 'purple'}}). Para qualquer atributo com espaço para nome (separado por dois pontos), por exemplo xlink:href, remova :e coloque em maiúscula a segunda parte do atributo, por exemplo xlinkHref. Aqui está um exemplo de uma SVG com <defs>, <use>e estilos inline:

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

Demonstração de código de trabalho

Para obter mais detalhes sobre suporte específico, consulte a lista de documentos de atributos SVG suportados . E aqui está o problema (agora fechado) do GitHub que rastreia o suporte a atributos SVG com espaço para nome.


Resposta anterior

Você pode fazer uma incorporação simples do SVG sem precisar usar dangerouslySetInnerHTMLapenas os atributos de espaço para nome. Por exemplo, isso funciona:

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

Nesse ponto, você pode pensar em adicionar adereços como fill, ou qualquer outra coisa que possa ser útil para configurar.

Andrew Patton
fonte
@ChinonsoChukwuogor Great question! Não sei, nunca usei o React Native. Você experimentou?
Andrew Patton
@AndrewPatton Vários nomes de classe Css com o tick char não funcionam: ' .class1, .class2{fill: #005baa;}' Como posso corrigir isso?
HelloWorld
@ HelloWorld Você pode me dar um exemplo em que não funciona? Eu só bifurcada minha demonstração original para adicionar classBe funcionou: codepen.io/acusti/pen/BVJzNg
Andrew Patton
Obrigado, a partir disso, eu consegui importar um svg do arquivo como um componente React sem nenhum carregador, apenas removi `` xmlns: osb = " openswatchbook.org/uri/2009/osb " `` `de a tag svg, deixando apenas os xlmns. É tudo sobre a análise de tags aparentemente. Por precaução, também segui estas etapas: blog.logrocket.com/how-to-use-svgs-in-react
Funder
56

Se você apenas possui uma sequência svg estática que deseja incluir, pode usar dangerouslySetInnerHTML:

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

e o React incluirá a marcação diretamente sem processá-la.

Sophie Alpert
fonte
3
Estou controlando alguns caminhos dentro do SVG usando o React, mas o React parece não suportar os elementos de filtro. Existe uma maneira de apoiar isso? Parece que perigosamente o SetInnerHTML não funcionará porque não posso colocar uma extensão dentro de um SVG e não posso usá-lo para definir o atributo de filtro nos caminhos. Suponho que não há uma maneira de criar elementos React como de costume, mas eles passam todos os atributos literalmente para os elementos DOM?
Andy
Em 2019, parece que você pode usar o SetInnerHTML perigosamente, mas ainda não consegui fazer o filtro de sombra funcionar no Chrome usando o SetInnerHTML perigosamente, mas está funcionando no Firefox.
Shnd 25/05/19
31

De acordo com um desenvolvedor de reagentes , você não precisa do espaço para nome xmlns. Se você precisar do atributoxlink:href poderá usar xlinkHref a partir de react 0.14

Exemplo

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

Se você deseja carregá-lo a partir de um arquivo, tente usar o React-inlinesvg - isso é bastante simples e direto.

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
fonte