Megan Pearson viser det hvordan du enkelt får SVG-ikoner inn i React. Foto: Harpal Singh / Unsplash
Megan Pearson viser det hvordan du enkelt får SVG-ikoner inn i React. Foto: Harpal Singh / UnsplashVis mer

Lag en inline SVG-komponent i React

Én React-komponent for hvilket som helst SVG-ikon i hvilken som helst farge.

SVG-er er fantastiske.

De er superskarpe og skalerbare. De kan manipuleres av CSS og/eller Javascript. De er tilgjengelige for skjermlesere og andre hjelpemidler.

De er spesielt kule og morsomme og lette å jobbe med når du kombinerer dem med gjenbrukbare React-komponenter.

Jeg lagde derfor en metode for å få SVG-ikoner i én React-komponent, som dette:

<Icon name="arrow" fill="pink" />
<Icon name="unicorn" fill="purple" />

Fordi jeg ville…

  • ...få både fordelene av inline SVG-er og gjenbruksverdien til React-komponenter
  • ...enkelt stile om og endre SVG-er der og da
  • ...slippe å ha store bolker med SVG-kode rett inne i React-componentene
  • ...slippe å importere massevis av SVG-er i ulike komponenter hele tida
  • ...bruke den samme komponenten for alle ikonene mine
  • ...kunne bruke oppdaterte filer fra designerne ved å bare slippe dem inn, i stedet for å måtte gjøre masse endringer

Prosessen

Jeg starta med å gjøre selve SVG-en til en komponent, som jeg kunne gi egenskaper for å stile den om inline.

For eksempel så hadde jeg et pil-ikon ✔ som jeg ville bruke om igjen med andre farger:

<ArrowIcon fill="#BCC614" / >

Dette er topp, men hva om jeg vil bruke et annet ikon (for eksempel en enhjørning 🦄) i Dashboard-komponenten? Det blir ganske overflødig å lage en helt ny komponent, akkurat som <ArrowIcon />, bare for å endre ikonet.

Så! Jeg lagde min gjenbrukbare <ArrowIcon /> mer fleksibel med en name-egenskap. Denne vil stemme overens med navnet til SVG-en, og bli brukt for å velge det riktige ikonet. For eksempel:

<Icon name="arrow" fill="#00ABB0" />
<Icon name="accepted" fill="#E89B5B" />
<Icon name="unicorn" fill="#B05BE8" />

Feller

Metoden har noen konsekvenser.

Fordi vi laster alle SVG-ene inn i samme komponent, kan det oppstå problemer om du har innført kodesplitting. Dette kan føre til at SVG-ene dupliseres på tvers av bundles. Det går trolig fint om du bare har et håndfull små SVG-er, men har du mange og store, kan det blåse opp koden din. Så metoden fungerer best for små til mellomstore prosjekter.

«Vurder om dette er akseptabelt»

I tillegg: Om det er fyll eller andre egenskaper i SVG-filene, kan de få forrang på grunn av spesifisitet. Derfor kan du trenge å fjerne dem fra selve SVG-en og ta høyde for dem i komponenten i stedet.

Denne metoden laster alle SVG-ene dine uansett om de brukes eller ikke. Vurder om dette er akseptabelt for prosjektet ditt.

Sikre at SVG-ene lastes riktig

Installer react-svg-loader og konfigurer den i webpack.config.js. For eksempel:

{
  module: {
    rules: [
      ...,
      {
        test: /\.svg$/,
        use: [{
          loader: 'react-svg-loader',
        }],
      },
      ...,
    ]
  }
}

Lag komponent for ett ikon

Lag en funksjonell komponent som bare returnerer pil-ikonet med en egenskap kalt "fill". Denne vil la oss endre fargene til ikonet. I dette eksempelet setter jeg standardfargen (en spennende neongrønn) om ingenting er spesifisert fra de andre komponentene:

import React from 'react';
import Arrow from './arrow.svg';

const ArrowIcon = ({ fill = '#5BE8AE' }) => {
  return(
    <Arrow fill={fill}/>
  );
};

Ta da! Dette er din gjenbrukbare, inline SVG-komponent. Du kan bruke den i alle andre komponenter ved å importere den og endre fargen med "fill"-egenskapen. Om vi vil ha en pil i <Dashboard />-komponenten vår, kan vi bruke den slik:

export default ArrowIcon;

import React from 'react';
import ArrowIcon from '../ArrowIcon';

const Dashboard = () => {
  <div>
    Some text with an arrow next to it <ArrowIcon fill="#666" />
  </div>
}

export default Dashboard;

Lag komponent alle ikoner

For å gjøre den eksisterende <ArrowIcon /> mer fleksibel, starter vi med å gi den navnet <Icon />. Så kan vi endre den slik:

import React from 'react';
import PropTypes from 'prop-types';

/* import all of the icons that you want to use */
import Arrow from './arrow.svg';
import Accepted from './accepted.svg';
import Rejected from './rejected.svg';
import Unicorn from './unicorn.svg';

/* create a function that will pick which icon to use */
const pickIcon = (name) => {
  switch(name) {
  case 'arrow': return Arrow;
  case 'accepted': return Accepted;
  case 'rejected': return Rejected;
  case 'unicorn': return Unicorn;
  default: throw new Error('no SVG for: ' + name);
  }
};

/* pass the name & fill props (that we will specify in our 
other components) to Icon to pick the right icon */
const Icon = ({ name, fill='#5BE8AE' }) => {
  const SVG = pickIcon(name);
  return(
    <SVG fill={fill}/>
  );
};

/* set the propTypes so we can catch bugs with typechecking */
Icon.propTypes = {
  name: PropTypes.string.isRequired,
  fill: PropTypes.string,
}

export default Icon;

Vakkert. Nå kan vi spesifisere hvilket ikon vi vil ha som en egenskap i komponenten, og stile den også. For eksempel, tilbake i <Dashboard />:

import React from 'react';
import Icon from '../Icon';

const Dashboard = () => {
  <div>
    <span>Text with an arrow <Icon name="arrow" fill="#666" /></span>
    <span>Here is our majestic <Icon name="unicorn" /></span>
  </div>
}

export default Dashboard;

Der har vi den... En gjenbrukbar, selvstendig, inline SVG-React-komponent! 😀