React-hook: Kopiere ting til utklipps­tavla

- Har vært mange… kreative metoder, skriver Kaptein Krok, som har en enklere løsning med Clipboard-API-et.

Kaptein Krok viser det hvordan du skriver en React-hook for å kopiere ting til utklippstavla. 📸: <a href="https://unsplash.com/@markusspiske?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Markus Spiske</a> / <a href="https://unsplash.com/s/photos/pirate?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a>
Kaptein Krok viser det hvordan du skriver en React-hook for å kopiere ting til utklippstavla. 📸: Markus Spiske / Unsplash Vis mer

Denne lille artikkelserien introduserer deg til en rekke små React hooks som er praktiske å ha i kodebasen din.

I denne episoden lager vi en fin måte å kopiere ting til utklippstavlen!

Gjør det enkelt å kopiere

En ting jeg ofte lager er det å kunne kopiere en lenke for å dele den med venner og kollegas.

Det finnes mange måter å gjøre det på, men jeg har en tendens til å lage meg en custom hook. Her skal vi gjøre nettopp det.

Vi starter med å definere APIet på hooken vår. Den blir egentlig enkelt nok:

const { copy, hasCopied } = useClipboard();

copy -funksjonen tar imot teksten som skal kopieres, og hasCopied er et flagg som sier om teksten har blitt kopiert eller ei. Sistnevnte flagg gjør at man kan gi brukeren feedback på at teksten har blitt kopiert!

Litt om det å kopiere tekst

Opp gjennom tidene har det vært mange… kreative måter å kopiere ting til utklippstavla.

Man har måttet sette inn et textarea-element, skjule det, fokusere det og kalle document.execCommand("copy") , gjøre ting på en egen måte i Internet Explorer, og i noen tilfeller også ty til (grøss) Flash.

Dagens løsning er heldigvis ganske mye enklere. Man kaller den asynkrone funksjonen navigator.clipboard.writeText med den teksten man vil lagre, og passer på at den ikke kaster noen exceptions.

Merk at navigator.clipboard.writeText ikke fungerer i IE11, så om applikasjonen din krever at dette støttes, så vil jeg anbefale pakken copy-to-clipboard , som implementerer noen fallbacks for eldre nettlesere. Men trenger egentlig IE11 støtte for enkel tekstkopiering? 🤔

Implementasjonstid!

La oss først se på hvordan vi implementerer copy-funksjonen:

const useClipboard = () => {
  const copy = React.useCallback(async (text) => {
    try {
      await navigator.clipboard.writeText(text);
    } catch {
      alert('Nettleseren din støtter ikke kopiering, dessverre');
    } 
  }, []);
  return { copy };
};

Her lager vi copy-funksjonen, som egentlig bare er en wrappet versjon av navigator.clipboard.writeText (eller copy-to-clipboard-biblioteket), hvor vi sier ifra om ting ikke fungerte som forventet.

Nå, la oss legge til støtte for å huske på om man har kopiert eller ei. Her pleier jeg som regel å bruke en såkalt timeout-funksjon, som tilbakestiller “har kopiert”-flagget etter et par sekunder, så man kan trykke på nytt om man vil.

Vi trenger en useState til å huske på om det har blitt kopiert, og en useEffect til å tilbakestille tilstanden etter noen sekunder.

const useClipboard = () => {
  const [hasCopied, setCopied] = React.useState(false);
  React.useEffect(() => {
    if (!hasCopied) return;
    let id = window.setTimeout(() => setCopied(false), 2000);
    return () => window.clearTimeout(id);
  }, [hasCopied]);

  const copy = React.useCallback(async (text) => {
    try {
      await navigator.clipboard.writeText(text);
      setCopied(true);
    } catch {
      alert('Nettleseren din støtter ikke kopiering, dessverre');
      setCopied(false);
    } 
  }, []);
  return { copy, hasCopied };
};

Og der har vi faktisk en helt komplett fungerende hook for å kopiere tekst! Her er hvordan man ville brukt den:

function Example() {
  const [text, setText] = React.useState("");
  const { copy, hasCopied } = useClipboard();
  return (
    <div>
      <h1>Kopieringseksempel</h1>
      <p>
        Skriv inn noe i feltet, og trykk på knappen 
        for å kopiere det til utklippstavlen din
      </p>
      <label>
        Hva vil du kopiere?
        <br />
        <input 
          value={text} 
          onChange={(e) => setText(e.target.value)} 
        />
      </label>
      <button 
        onClick={() => copy(text)}
        disabled={hasCopied}
        type="button"
       >
        {hasCopied ? "Kopiert!" : "Kopier"}
      </button>
    </div>
  );
}

Flere features?

Clipboard-API-et er nytt, og det er ikke alt som er støttet overalt.

Når det er sagt, er det relativt trivielt å kunne kopiere arbitrære filer som bilder, lydfiler eller PDF-dokumenter via den beslektede funksjonen navigator.clipboard.write.

I tillegg så kan man jo legge til støtte for å endre lengden tid det tar før hasCopied -flagget tilbakestilles etter et klikk. Jeg ville nok prøvd å holde det likt innenfor én applikasjon, men det vet du helt sikkert best selv.

Har du en krok-idé?

Jeg har en rekke enkle hooks som er greie å ha i verktøykassa. Om du har en du er spesielt fornøyd med, så send meg en mail — så kan det godt hende den dukker opp i denne serien!