React Hooks — vad är det, grundläggande hooks och användningsregler

Författare: IT Sectr Publicerad: 2026-07-04 Lästid: 10 min

React Hooks — är funktioner som gör att du kan använda tillstånd, effekter, kontext och andra React-funktioner i funktionella komponenter, utan att skriva klasser. Introducerade i React 16.8 har hooks radikalt förändrat utvecklingsmetoden genom att ersätta komplexa mönster som HOC och render props. Enligt React, 2024 finns det 15 inbyggda hooks som täcker alla scenarier för komponenthantering.

Huvudsakligt

  • Hooks — funktioner för att koppla React-funktioner till funktionella komponenter utan extends Component.
  • useState — grundläggande hook för tillståndshantering, returnerar värde och setter.
  • useEffect — för sidoeffekter: API-anrop, prenumerationer, timers, DOM-manipulationer.
  • useContext — för åtkomst till React-kontext utan Consumer-omslag och static contextType.
  • Regler för hooks — anropa endast på högsta nivån och endast inom funktionella komponenter eller anpassade hooks.

Vad är React Hooks?

React Hooks — en uppsättning inbyggda funktioner i React som gör att du kan ‘ansluta’ till ramverkets interna mekanismer utan att skapa klasser. Före React 16.8 kunde funktionella komponenter endast ta emot props och returnera JSX — all komplex logik krävde en klasskomponent.

Problemet med klasskomponenter — separation av relaterad logik. Kod som tillhörde en enhet (till exempel en WebSocket-prenumeration) tvingades delas mellan componentDidMount, componentDidUpdate och componentWillUnmount. Hooks löser detta: all logik grupperas i en useEffect.

Det andra problemet — återanvändning av logik. För återanvändning av tillståndslogik mellan klasskomponenter var man tvungen att tillämpa HOC (högre ordningens komponenter) eller render props — båda mönstren skapade extra nästling i komponentträdet. Anpassade hooks löser detta problem utan nästling.

useState — tillståndshantering

useState — den mest grundläggande hooken. Den accepterar ett initialvärde och returnerar en tuple: det aktuella värdet och en funktion för att uppdatera det. Till skillnad från this.setState i klasser slår useState inte samman objekt — det nya tillståndet ersätter helt det föregående för ett specifikt anrop till useState.

js
import React, { useState } from 'react';

function Form() {
  const [text, setText] = useState('');
  const [submitting, setSubmitting] = useState(false);

  async function handleSubmit() {
    setSubmitting(true);
    await fetch('/api/submit', {
      method: 'POST',
      body: JSON.stringify({ text })
    });
    setSubmitting(false);
  }

  return (
    <div>
      <input
        value={text}
        onChange={e => setText(e.target.value)}
      />
      <button onClick={handleSubmit}
        disabled={submitting}>
        {submitting ? 'Saving...' : 'Submit'}
      </button>
    </div>
  );
}

Funktionell form av setState

Setter för useState kan acceptera en funktion som tar emot det föregående värdet och returnerar ett nytt. Funktionell form är obligatorisk när det nya tillståndet beräknas från det föregående och batchade setState-anrop är möjliga — varje anrop får det aktuella föregående värdet.

useEffect — sidoeffekter och livscykel

useEffect — hook för att utföra sidoeffekter i funktionella komponenter. Den accepterar två argument: en effektfunktion och en beroendematris. React kör effekten efter varje render, men när beroenden anges — endast när något av dem har ändrats.

En tom beroendematris [] innebär att effekten körs en gång efter den första rendern (analogt med componentDidMount). Att returnera en funktion från effekten är cleanup, som körs vid avmontering (analogt med componentWillUnmount) och före återkörning av effekten.

js
import React, { useState, useEffect } from 'react';

function ChatRoom({ roomId }) {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const socket = new WebSocket(`wss://chat/${roomId}`);

    socket.onmessage = (event) => {
      setMessages(prev => [...prev, JSON.parse(event.data)]);
    };

    // Cleanup - stäng socket
    return () => socket.close();
  }, [roomId]);

  return <ul>
    {messages.map((msg, i) =>
      <li key={i}>{msg.text}</li>
    )}
  </ul>;
}

Beroenden för useEffect — är den enda kopplingen mellan effekten och omvärlden. Om en variabel från props eller tillstånd används i effekten måste den finnas i beroendematrisen. Att ignorera denna regel är källan till buggar med inaktuell data (stale closure).

useContext — åtkomst till kontext

useContext — hook för att läsa kontextvärdet. Den accepterar kontextobjektet som skapats med React.createContext och returnerar det aktuella värdet. Om kontexten ändras, renderas komponenten automatiskt om med det nya värdet.

Innan useContext kom, krävde åtkomst till kontext i funktionella komponenter en omslag i Context.Consumer, vilket skapade nästling. useContext eliminerar helt Consumer — det räcker att anropa hooken var som helst i den funktionella komponenten.

js
import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('ljus');

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return <button
    className={`btn btn-${theme}`}
  >
    {theme === 'dark' ? 'moon' : '☀️'}
  </button>;
}

useContext är inte en ersättning för Redux eller globalt tillstånd. React rekommenderar att använda kontext för sällan föränderliga värden — tema, språk, auktorisering. För ofta uppdaterad data kommer varje omrendering att beräkna om alla konsumenter av kontexten, vilket kan minska prestandan.

useReducer — komplex tillståndslogik

useReducer — alternativ till useState för tillstånd med komplex uppdateringslogik. Den accepterar en reducer-funktion och ett initialtillstånd, returnerar det aktuella tillståndet och en dispatch-funktion. Reducer tar emot aktuellt tillstånd och handling, returnerar ett nytt tillstånd — en ren funktion utan sidoeffekter.

useReducer är särskilt användbart när flera handlingar (set, reset, increment, addItem) hanterar ett tillstånd. Istället för flera useState med olika setters — en reducer med tydliga handlingstyper. Detta gör logiken förutsägbar och lätt att testa.

js
import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + 1 };
    case 'setStep':
      return { ...state, step: action.step };
    case 'reset':
      return { count: 0, step: 1 };
    default:
      throw new Error('Unknown action: ' + action.type);
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, {
    count: 0,
    step: 1
  });

  return (
    <>
      <p>Count: {state.count}</p>
      <button
        onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button
        onClick={() => dispatch({ type: 'reset' })}>Reset</button>
    </>
  );
}

useRef, useMemo, useCallback — optimering

useRef skapar ett föränderligt objekt som bevaras mellan renders. Ändring av current orsakar inte omrendering. Huvudtillämpning — åtkomst till DOM-element och lagring av muterbara värden (timers, tidigare värden, biblioteksinstanser).

useMemo memoizerar resultatet av en funktion. Den räknar om värdet endast när ett av beroendena ändras. Använd för dyra beräkningar — filtrering av stora arrayer, sortering, formatering av data. useCallback — ett specialfall av useMemo för memoizering av funktioner.

js
import React, { useRef, useMemo, useCallback } from 'react';

function SearchPage({ items, query, onItemSelect }) {
  const inputRef = useRef(null);

  // Autofokus vid montering
  useEffect(() => {
    inputRef.current?.focus();
  }, []);

  // Memorera filtrerat resultat
  const filtered = useMemo(() => {
    return items.filter(item =>
      item.name.toLowerCase()
        .includes(query.toLowerCase())
    );
  }, [items, query]);

  // Memorera callback
  const handleSelect = useCallback((id) => {
    onItemSelect(id);
  }, [onItemSelect]);

  return (
    <div>
      <input ref={inputRef}
        value={query}
        onChange={e => setQuery(e.target.value)}
      />
      <ul>
        {filtered.map(item =>
          <li key={item.id}>
            <button
              onClick={() => handleSelect(item.id)}>
              {item.name}
            </button>
          </li>
        )}
      </ul>
    </div>
  );
}

Viktig regel: useRef, useMemo och useCallback — optimeringsverktyg, inte obligatoriska konstruktioner. Slå inte in allt i useMemo — mät först prestandan. För tidig optimering komplicerar koden. React renderar komponenter snabbt; useMemo behövs bara när beräkningar verkligen är dyra (O(n²) och högre).

Regler för hooks och vanliga misstag

React införde två strikta regler för hooks. Första: anropa hooks endast på högsta nivån — inte inuti villkor, loopar eller nästlade funktioner. Andra: anropa hooks endast från React funktionella komponenter eller anpassade hooks. ESLint-plugin eslint-plugin-react-hooks kontrollerar automatiskt båda reglerna.

Det vanligaste misstaget — brott mot anropsordningen för hooks. React förlitar sig på anropsordningen för hooks mellan renders. Om en hook finns inuti ett villkor och inte anropades i en av renders, flyttas alla efterföljande hooks, vilket orsakar buggar.

MisstagVad händerLösning
Hook i villkorHook-ordningen brytsFlytta villkorslogiken inuti hooken
Stale closureEffekten använder gammalt värdeLägg till alla beroenden i matrisen
Oändlig loopuseEffect utan beroenden ändrar tillståndAnge beroenden eller använd useReducer
Ändra ref i renderSidoeffekt i funktionskroppenFlytta mutationer till useEffect

Det andra vanliga misstaget — stale closure i useEffect. Om en variabel som inte anges i beroendena används i effekten, ‘fångar’ effekten dess värde vid skapandet av slutningen. Lösning — inkludera alltid alla använda variabler i beroendematrisen. Om det finns för många beroenden, dela upp effekten i flera delar.

Vanliga frågor

Varför kan hooks inte anropas i villkor?

React förlitar sig på anropsordningen för hooks mellan renders. Om en hook anropades i ett villkor och inte fungerade i en av renders, ‘glider’ alla efterföljande hooks — deras tillstånd blandas. ESLint-regeln hooks/exhaustive-deps varnar för detta.

Vad är skillnaden mellan useEffect och useLayoutEffect?

useLayoutEffect är synkron och körs innan webbläsaren ritar ändringarna. useEffect är asynkron — efter ritning. Använd useLayoutEffect endast när du behöver mäta eller ändra DOM innan användaren ser ändringarna (popover-position, återställning av scroll).

Hur avbryter man en fetch-förfrågan vid avmontering?

Använd AbortController inuti useEffect. Skapa en controller, skicka signal till fetch och i cleanup-funktionen anropa controller.abort(). För äldre webbläsare räcker en cancelled-flagga: return () => { cancelled = true; } med kontroll före setState.

Vad är en anpassad hook och när skapar man den?

Anpassad hook — en JavaScript-funktion med prefixet use som använder inbyggda hooks. Skapa den när samma logik med hooks upprepas i två eller fler komponenter. Exempel: useDebounce, useLocalStorage, useMediaQuery. Anpassade hooks ersätter HOC och render props.

Varför körs useEffect två gånger i Strict Mode?

I Strict Mode monterar och avmonterar React avsiktligt komponenten två gånger i utvecklingsläge för att hitta fel med orensade effekter. Om cleanup är korrekt skriven orsakar inte dubbelanropet problem. I produktionsläge händer detta inte.

Sammanfattning

  • React Hooks — funktioner för att använda tillstånd, effekter och kontext i funktionella komponenter, som ersatte klasser.
  • useState — grundläggande hook för lokalt tillstånd med funktionell setter för säkra uppdateringar.
  • useEffect — universell hook för sidoeffekter med beroendematris och cleanup-funktion.
  • useContext — direkt åtkomst till React-kontext utan Consumer-omslag och extra nästling.
  • useReducer — för komplex tillståndslogik med handlingstyper, alternativ till Redux inom en komponent.
  • useRef, useMemo, useCallback — optimeringsverktyg: DOM-referenser, memoizering av värden och callbacks.
  • Högsta-nivån-regel — strikt begränsning av anrop av hooks utanför villkor, loopar och nästlade funktioner.

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också