Incorporer SVG dans ReactJS

127

Est-il possible d'incorporer du balisage SVG dans un composant ReactJS?

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

Résultats dans l'erreur:

Les attributs d'espace de noms ne sont pas pris en charge. ReactJSX n'est pas XML.

Quelle est la manière la plus légère de faire cela. Utiliser quelque chose comme React ART est bien exagéré pour ce que j'essaie de faire.

Nicolas
la source
1
Pouvez-vous créer un jsbin? Cela peut être aussi simple que de changer votre balise SVG d'ouverture en juste <svg id="Layer_1">(ou encore mieux, sans l'ID). Edit: voici un exemple: jsbin.com/nifemuwi/2/edit?js,output
Brigand
@FakeRainBrigand Merci! C'était aussi simple que ça dans ce cas. Regardez la réponse de Ben cependant. Il est bon de savoir que vous pouvez contourner l'analyse jsx lorsque vous en avez besoin.
nicholas

Réponses:

178

Mise à jour 27/05/2016

Depuis React v15, la prise en charge de SVG dans React est (proche de?) 100% de parité avec la prise en charge actuelle du navigateur pour SVG ( source ). Il vous suffit d'appliquer quelques transformations de syntaxe pour le rendre compatible JSX, comme vous devez déjà le faire pour HTML ( classclassName, style="color: purple"style={{color: 'purple'}}). Pour tout attribut d'espacement de nom (séparé par deux-points), par exemple xlink:href, supprimez le :et mettez en majuscule la deuxième partie de l'attribut, par exemple xlinkHref. Voici un exemple d'un svg avec <defs>, <use>et les styles en ligne:

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

Démo de travail codepen

Pour plus de détails sur la prise en charge spécifique, consultez la liste des attributs SVG pris en charge dans la documentation . Et voici le problème (maintenant fermé) de GitHub qui suivait la prise en charge des attributs SVG avec espace de nom.


Réponse précédente

Vous pouvez faire une simple intégration SVG sans avoir à l'utiliser dangerouslySetInnerHTMLen supprimant simplement les attributs de l'espace de noms. Par exemple, cela fonctionne:

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

À quel point vous pouvez penser à ajouter des accessoires comme fill , ou tout ce qui pourrait être utile à configurer.

Andrew Patton
la source
@ChinonsoChukwuogor Excellente question! Je ne sais pas, je n'ai jamais utilisé React Native. Avez-vous essayé?
Andrew Patton
@AndrewPatton Plusieurs noms de classes Css avec la coche ne fonctionnent pas: ' .class1, .class2{fill: #005baa;}' Comment puis-je résoudre ce problème?
HelloWorld
@HelloWorld Pouvez-vous me donner un exemple où cela ne fonctionne pas? Je viens de bifurquer ma démo originale pour l'ajouter classBet cela a fonctionné: codepen.io/acusti/pen/BVJzNg
Andrew Patton
Merci, à partir de là, j'ai réussi à importer un svg d'un fichier en tant que composant React sans aucun chargeur, je viens de supprimer `` `` xmlns: osb = " openswatchbook.org/uri/2009/osb " `` `de la balise svg, ne laissant que les xlmns. Il s'agit apparemment d'analyser les balises. Juste au cas où, j'ai également suivi ces étapes: blog.logrocket.com/how-to-use-svgs-in-react
Funder
56

Si vous avez juste une chaîne svg statique que vous souhaitez inclure, vous pouvez utiliser dangerouslySetInnerHTML:

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

et React inclura le balisage directement sans le traiter du tout.

Sophie Alpert
la source
3
Je contrôle certains chemins dans SVG en utilisant React, mais React ne semble pas prendre en charge les éléments de filtre. Y a-t-il un moyen de soutenir cela? On dirait que dangerouslySetInnerHTML ne fonctionnera pas car je ne peux pas mettre de span dans un SVG et je ne peux pas l'utiliser pour définir l'attribut de filtre sur les chemins. Je ne suppose pas qu'il existe un moyen de créer des éléments React comme d'habitude, mais leur faire passer tous les attributs textuellement aux éléments DOM?
Andy
En 2019, il semble que vous puissiez utiliser dangerouslySetInnerHTML mais je ne pouvais toujours pas faire fonctionner le filtre d'ombre sur Chrome en utilisant dangerouslySetInnerHTML, mais cela fonctionne sur Firefox.
Shnd
31

Selon un développeur React , vous n'avez pas besoin de l'espace de noms xmlns. Si vous avez besoin de l'attribut, xlink:hrefvous pouvez utiliser xlinkHref de react 0.14

Exemple

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

Si vous souhaitez le charger à partir d'un fichier, vous pouvez essayer d'utiliser React-inlinesvg - c'est assez simple et direct.

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
la source