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! 😀