React sine Hooks lar deg hooke på funksjonalitet. 📸: Efe Kurnaz / Unsplash
React sine Hooks lar deg hooke på funksjonalitet. 📸: Efe Kurnaz / Unsplash Vis mer

Slik bruker du nye React Hooks

React Hooks er her for å bli  —  dette er hva det betyr for deg.

I år som i fjor var den “offisielle” React-konferansen ReactConf et spetakkel uten like, med haugevis av spekulasjoner og hype opp mot hva som viste seg å bli et to dagers nyhetsmaraton i Las Vegas, Nevada. Da støvet hadde lagt seg stod vi igjen med et React-miljø i ekstase. Twitter kokte. GitHub bobla. Og fremtiden har aldri sett lysere ut for oss utviklere.

Dan Abramov, på vegne av hele React-teamet, presenterte en måte å bruke tilstand, lifecycle-funksjoner og andre klassespesifikke features i funksjonskomponenter. De kaller det Hooks.

Denne artikkelen kommer til å gi deg en rask oppsummering av hva hooks er, hvordan du bruker dem og hvorfor du ikke burde… helt ennå.

Hva er en «hook»?

En hook er en funksjon som gir tilgang til React-features, som tidligere kun var tilgjengelige i klassekomponenter, i funksjonskomponenter. De gir funksjonskomponentene dine superkrefter, og muliggjør deling av funksjonalitet på helt nye og spennende måter.

Selv om dette kun er et forslag (med tilhørende RFC) — og ikke noe man skal bruke i produksjon helt ennå — har React-teamet gjort det enkelt å bli kjent med dette nye konseptet via de nye dokumentasjonssidene de har publisert om emnet.

Dokumentasjonen er god, lang og utførlig, og vi anbefaler deg definitivt å ta deg tiden til å skumlese gjennom ved nærmeste anledning. I mellomtiden har vi skrevet en liten guide til deg som forklarer det mest grunnleggende APIet. La oss stupe inn!

useState

Funksjonskomponenter med tilstand blir muliggjort med den nye funksjonen useState. Slik ser den ut:

import { useState } from "react";
const StatefulComponent = props => {
  const initialState = '';
  const [input, setInput] = useState(initialState);
  
  return (
    <input 
      value={input} 
      onChange={e => setInput(e.target.value)} 
    />
  );
};

useState tar den initielle tilstanden som argument, og returnerer et array med nåværende tilstand og en funksjon for å oppdatere tilstanden. På samme måte som for klassekomponenter, aksepterer setState både en verdi og en callback som får nåværende tilstand som et argument. Man kan kalle på useState flere ganger i et funksjonskomponent for å få flere uavhengige tilstandsverdier. Med andre ord kan man typisk kalle useState for hver verdi man ønsker i tilstanden sin.

useEffect

Se for deg at du har et komponent som er avhengig av å hente data fra et endepunkt eller som lytter etter hendelser som endring av størrelsen til vinduet. Da ender man opp med effekter som er spredt utover componentDidMount, componentDidUpdate og componentWillUnmount.

useEffect forenkler disse tilfellene. Effekter som skal skje hver gang en prop endrer seg er enkle funksjoner som kjører etter hver render.

import { useState, useEffect } from "react";
const StatefulComponentWithEffect = props => {
  const [input, setInput] = useState('');
  // Tilsvarende componentDidMount og componentDidUpdate
  useEffect(() => {
    document.title = input;
  })
  
  return (
    <input 
      value={input}
      onChange={e => setInput(e.target.value)} 
    />
  );
};

Når det kommer til henting av data så ønsker man ikke at dette skal skje etter hver render. For å hindre dette kan man sende med en liste og effekten vil kun kjøres på nytt hvis en av verdiene i listen endrer seg.

import { useState, useEffect } from "react";
const ComponentWithFetch = ({ id, query }) => {
  const [state, setState] = useState({});
  useEffect(() => {
    fetch(`/api/${id}?query=${query}`)
      .then(data => setState(data))
  }, [id, query])
  
  return (
    <div>
      {state.someData}
    </div>
  );
};

For effekter som lytter på hendelser, eller trenger en opprydding av en eller annen grunn, kan man returnere en funksjon fra useEffect til å rydde opp.

const ComponentWithSubscription = () => {
  const [state, setState] = useState({});
  useEffect(() => {
    // Tilsvarende componentDidMount
    eventBus.subscribe(data => setState(data));
// Tilsvarende componentWillUnmount
    return () => {
      eventBus.unsubscribe();
    };
  });
  return (
    <div>
      {state.someData}
    </div>
  );
};

Flere hooks

I tillegg til useState og useEffect har man en smørbrødliste med andre hooks å velge mellom. Vi anbefaler deg virkelig å sjekke ut hva de har å tilby.

Lag dine egne hooks

Spenn deg fast, for det er her moroa virkelig begynner! Hooks er ikke direkte koblet til et komponent, og man kan gjenbruke de på tvers av komponenter. Dette legger til rette for kraftige nye måter å abstrahere funksjonalitet ved å kombinere hooks ut i egne funksjoner. Fett!

Si at vi ønsker å ha tilgang til vindusstørrelsen i flere komponenter. Da kan vi lage en hook som holder på størrelsen og endrer den når vinduet endrer seg ved å kombinere useState og useEffect.

import { useState, useEffect } from "react";
const getSize = () => ({
  innerHeight: window.innerHeight,
  innerWidth: window.innerWidth,
})
export const useWindowSize = () => {
  let [size, setSize] = useState(getSize());
  const updateSize = () => setSize(getSize());
  useEffect(() => {
    window.addEventListener('resize', updateSize);
    return () => {
      window.removeEventListener('resize', updateSize);
    };
  });
  return size;
}

Denne hooken kan man enkelt gjenbruke på tvers av komponenter.

React teamet oppfordrer sterkt til at man prefikser hooks med use slik at man sender et tydelig signal om hvordan oppførsel funksjonen tilfører.

Vi er veldig gira på denne måte å dele funksjonalitet på. Det løser mange av utfordringene med høyereordens komponenter. Man skriver mindre kode, det er færre begrensinger og man mounter færre komponenter.

Hva betyr dette egentlig for meg?

Helt siden React 16 kom ut i september i fjor har det kommet nesten månedlige nyheter fra React-teamet hos Facebook. Hvorfor er nettopp dette en nyhet som kan snu opp ned på utviklerhverdagen din?

Lettere å dele tilstandslogikk

En av de største utfordringene Hooks løser for React, er hvordan man deler logikk som involverer en eller annen form for tilstand. Frem til nå har vi enten brukt høyere-ordens komponenter (HOCs) eller render-prop teknikken. Dette fungerer jo i og for seg, men det fører enten til veldig dype komponenttrær som er vanskelige å debugge, eller hva som har blitt omtalt som en syntakseksplosjon.

Custom hooks løser begge disse problemene på en relativt elegant måte. Siden custom hooks er definert som funksjoner som starter med “use” og som kaller andre hooks, er de enkle å refaktorere ut, teste isolert og ikke minst dele. Det har allerede dukket opp flere biblioteker med gjenbrukbare hooks for integrasjoner med DOMens mange imperative APIer — og mange flere vil nok komme.

Mindre refaktorering

Et av de største smertepunktene med funksjonskomponentene til React er når man plutselig trenger tilstand eller tilgang til en lifecycle-funksjon. Da må man plutselig refaktorere seg over til klassesyntaksen, som kan være forvirrende i pull requests og slitsomt å gjøre (det finnes faktisk en VSCode plugin som gjør dette for oss).

Med hooks trenger man ikke lenger å bruke klasser. Siden alt du får fra klassekomponenter nå er (eller blir) tilgjengelig via hooks, kan man heller dra inn det man trenger, og unngå masse ekstra støy i kodebasen din.

Unngå å spre logikken din

En annen rettmessig klage på React er måten logikk ofte ble spredt på tvers av React sine lifecycle-funksjoner. Det er ikke lenger et problem med Hooks.

Siden useEffect -hooken kan rydde opp etter seg selv, og kjører opp til hver eneste gang komponenten rendres, kan man gruppere alt på ett sted! Dette gjør det lettere å følge en feature, lettere å unngå bugs, og ikke minst lettere å forstå kode.

Her er en tweet som viser hvor stor denne forbedringen er — adaptert av koden Dan Abramov viste i sin keynote om temaet:

Ikke skriv om eksisterende kode (ennå)

Det er spennende med mye features — men selv med all hype og oppmerksomhet React sine nye hooks har fått de siste dagene, er det fortsatt kun et proposal, og kun tilgjengeliggjort i en tidlig alpha-versjon av react@16.7. Med andre ord — ta noen dype pust, og la omskrivningstrangen ligge i noen uker eller måneder til.

Istedenfor anbefaler vi (og React) å leke litt med hooks, og prøve å bli vant til denne nye måten å tenke på. Det er overraskende enkelt, takket være codesandbox.io og andre online editors. Du får tilgang til hele Hooks-APIet ved å installere next-taggen til React og React DOM, slik:

npm i react@next react-dom@next

Prøv å lag noe morsomt, teit, spennende og helt bortkasta. Her er en spinner som lar deg slå ihjel litt tid med tilfeldige “vent litt”-meldinger:

Vi er helt hooka!

Hooks er nok et paradigmeskifte for React —og et som kommer til å lette både utvikling og forvaltning av appene våre i tiden fremover. Nye muligheter vil åpne seg — og den virkelige spennende innovasjonen kommer vi nok til å se fra miljøet rundt React.

Start helgen med å se presentasjonen til Sophie Alpert og Dan Abramov, og dykk ned i den veldig lettleste, men fyldige, dokumentasjonen som allerede er publisert. Og bli helt hooka, du også.