Separering av bekymmer med React hooks PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Separering av problem med React-krokar

Om du har arbetat med React ett tag har du förmodligen stött på behållare och presentationskomponenter , eller smarta och dumma komponenter. Dessa termer beskriver en mönster som skiljer UI-lagret av React-komponenter från logiken.

Att separera användargränssnittet från affärslogiken är inget unikt för React: separation av bekymmer är en designprincip som har funnits redan på 70-talet. Till exempel är det vanligt att separera koden som kommer åt databasen från affärslogiken på backend.

Så i React löste vi det här problemet genom att skapa containerkomponenter som innehåller all logik, som sedan skickar data via rekvisita till presentationskomponenten.

Med introduktionen av React-krokar finns det ett nytt tillvägagångssätt för detta: att använda anpassade krokar.

Varför ska vi skilja logiken från komponenten?

Innan vi börjar koppla bort logiken från våra React-komponenter bör vi veta varför.

Att organisera vår kod på ett sätt där varje funktion eller komponent bara ansvarar för en sak har fördelen att det är mycket lättare att förändra och underhålla (Dave och Andrew kallar detta "ortogonalitet” i deras bok Den pragmatiska programmeraren).

Att tillämpa detta på React innebär att vår komponent kommer att se renare och mer organiserad ut. Vi behöver till exempel inte bläddra förbi logikens vägg innan vi redigerar användargränssnittet.

Att organisera din kod på det här sättet gör det inte bara bättre och lättare att navigera, det gör det också lättare att ändra eftersom att byta kroken inte påverkar användargränssnittet och vice versa.

Testning är också mer tillgänglig: vi kan testa logiken separat från användargränssnittet om vi vill. Den viktigaste fördelen för mig är dock hur detta tillvägagångssätt organiserar min kod.

Hur man kopplar bort logik med React-krokar

För att koppla bort logiken från vår komponent kommer vi först att skapa en anpassad krok.

Låt oss ta denna komponent som ett exempel. Den beräknar exponentialvärdet för bastalet och exponenten:

Du kan hitta hela källkoden här..

Koden ser ut som följande:

export const ExponentCalculator = () => {
  const [base, setBase] = useState(4);
  const [exponent, setExponent] = useState(4);
  const result = (base ** exponent).toFixed(2);

  const handleBaseChange = (e) => {
    e.preventDefault();
    setBase(e.target.value);
  };

  const handleExponentChange = (e) => {
    e.preventDefault();
    setExponent(e.target.value);
  };

  return (
    <div className="blue-wrapper">
      <input
        type="number"
        className="base"
        onChange={handleBaseChange}
        placeholder="Base"
        value={base}
      />
      <input
        type="number"
        className="exponent"
        onChange={handleExponentChange}
        placeholder="Exp."
        value={exponent}
      />
      <h1 className="result">{result}</h1>
    </div>
  );
};

Det här kan redan se bra ut, men bara för den här handledningens skull bild att det finns mer logik här.

Som ett första steg kommer vi att göra det flytta logiken till en anpassad krok och kalla det inuti vår komponent.

const useExponentCalculator = () => {
  const [base, setBase] = useState(4);
  const [exponent, setExponent] = useState(4);
  const result = (base ** exponent).toFixed(2);

  const handleBaseChange = (e) => {
    e.preventDefault();
    setBase(e.target.value);
  };

  const handleExponentChange = (e) => {
    e.preventDefault();
    setExponent(e.target.value);
  };

  return {
    base,
    exponent,
    result,
    handleBaseChange,
    handleExponentChange,
  };
};

export const ExponentCalculator = () => {
  const {
    base,
    exponent,
    result,
    handleExponentChange,
    handleBaseChange,
  } = useExponentCalculator();

  // ...
};

Vi skulle kunna flytta den här kroken till en separat fil för en mer framträdande åtskillnad av bekymmer.

Dessutom kan vi dela upp vår krok ytterligare i mindre, återanvändbara funktioner. I det här fallet kan vi bara extrahera calculateExponent.

useExponentCalculator.js

const calculateExponent = (base, exponent) => base ** exponent;

const useExponentCalculator = () => {
  const [base, setBase] = useState(4);
  const [exponent, setExponent] = useState(4);
  const result = calculateExponent(base, exponent).toFixed(2);

  // ...
};

Att testa dessa funktioner är mycket lättare än att testa hela komponentens kod från det första exemplet. Vi skulle kunna testa dem med vilket Node.js-testbibliotek som helst, som inte ens behöver stödja React-komponenter.

Vi har nu vår ramspecifika kod (React) i koden för komponenten och kroken, medan vår affärslogik bor i de olika funktioner vi definierade senare (som är ramagnostiska).

Bästa praxis

Namnge

Jag gillar att döpa mina anpassade krokar efter komponenten som en sammanlänkning av use och komponentens namn (t.ex useExponentCalculator). Jag ringer då fil detsamma som kroken.

Du kanske vill följa en annan namnkonvention, men jag rekommenderar hålla sig konsekvent i ditt projekt.

Om jag kan återanvända delar av en anpassad krok, brukar jag flytta den till en annan fil under src/hooks.

Överdriv inte det

Försök att vara pragmatisk. Om en komponent bara har några rader JS, är det inte nödvändigt att separera logiken.

CSS-i-JS

Om du använder ett CSS-in-JS-bibliotek (useStyles), kanske du vill flytta den här koden till en annan fil också.

Du kan flytta den till samma fil som kroken. Jag föredrar dock att antingen behålla den ovanför komponenten i samma fil eller flytta den till en egen fil om den blir för stor.

Slutsats

Oavsett om du tror att användningen av anpassade krokar förbättrar din kod eller inte, i slutändan beror det på personliga preferenser. Om din kodbas inte innehåller mycket logik, kommer fördelarna med detta mönster inte att vara alltför relevanta för dig.

Anpassade krokar är bara ett sätt att öka modulariteten; Jag skulle också starkt rekommendera dela upp komponenter och funktioner i mindre, återanvändbara bitar när det är möjligt.

Ämnet diskuteras också på en mer generell nivå i Den pragmatiska programmeraren. Jag skrev en artikel som täcker mina favoritämnen i boken, så om det intresserar dig, se till att göra det titta på det där.

Tidsstämpel:

Mer från Codementor React Fakta