Codest
  • Om oss
  • Tjänster
    • Utveckling av programvara
      • Frontend-utveckling
      • Backend-utveckling
    • Staff Augmentation
      • Frontend-utvecklare
      • Backend-utvecklare
      • Dataingenjörer
      • Ingenjörer inom molntjänster
      • QA-ingenjörer
      • Övriga
    • Det rådgivande
      • Revision och rådgivning
  • Industrier
    • Fintech & bankverksamhet
    • E-commerce
    • Adtech
    • Hälsoteknik
    • Tillverkning
    • Logistik
    • Fordon
    • IOT
  • Värde för
    • VD OCH KONCERNCHEF
    • CTO
    • Leveranschef
  • Vårt team
  • Fallstudier
  • Vet hur
    • Blogg
    • Möten
    • Webbinarier
    • Resurser
Karriär Ta kontakt med oss
  • Om oss
  • Tjänster
    • Utveckling av programvara
      • Frontend-utveckling
      • Backend-utveckling
    • Staff Augmentation
      • Frontend-utvecklare
      • Backend-utvecklare
      • Dataingenjörer
      • Ingenjörer inom molntjänster
      • QA-ingenjörer
      • Övriga
    • Det rådgivande
      • Revision och rådgivning
  • Värde för
    • VD OCH KONCERNCHEF
    • CTO
    • Leveranschef
  • Vårt team
  • Fallstudier
  • Vet hur
    • Blogg
    • Möten
    • Webbinarier
    • Resurser
Karriär Ta kontakt med oss
Pil tillbaka GÅ TILLBAKA
2021-12-07
Utveckling av programvara

En djupare titt på de mest populära React-krokarna

Codest

Pawel Rybczynski

Software Engineer

Under många intervjuer har jag märkt att även erfarna programmerare har problem med att skilja på Hooks, för att inte tala om deras mer avancerade funktioner. Så jag kommer att försöka förklara i den här artikeln hur Hooks ska användas.

De viktigaste sakerna du behöver komma ihåg om Hooks:

  • de kan endast användas i funktionskomponenter - klasskomponenter har egen livscykelimplementering;
  • de börjar alltid med användning;
  • kan du använda hur många Hooks du vill, men du måste komma ihåg att användningen av dem påverkar den totala prestandan;
  • de måste utföras i samma ordning vid varje rendering ... men varför? Låt oss ta en titt på ett exempel:
importera { useState,useEffect } från "react";

export standardfunktion FunctionComponent() {
const [value, setValue] = useState(1);
const [doubleValue, setDoubleValue] = useState(1);
if (värde > 3) {
  useEffect(() => setDoubleValue(värde * 2),[värde]);
}

return (
  <>
    <p>{`Enkel ${värde} Dubbel ${doubleValue}`}</p>
    <button onclick="{()" > setValue(värde + 1)}&gt;Kontroll</button>
  </>
);
}
```

Först kommer du att få en varning från eslint:

<code>srcFunctionKomponent.js
   Rad 11:5: React Kroken "useEffect" anropas villkorligt. <strong>React Krokar</strong> måste anropas i exakt samma ordning i varje komponent som renderas .eslintreact-hooks/rules-of-hooks

Som du kan se är det bara en eslint-varning, så du kan inaktivera den genom att lägga till ett kommando underifrån högst upp i Funktionskomponent

/* eslint-avaktivera react-hooks/rules-of-hooks */ 

och det kommer att fungera men bara tills vi uppfyller villkoret som kör vår Hook. Det allra nästa som vi kommer att se är detta fel.

Fel som inte upptäcktes: Renderade fler krokar än under föregående rendering.
     React 5
     Funktionskomponent Funktionskomponent.js:11
     React 12
     unstable_runWithPriority scheduler.development.js:468
     React 17
     js index.js:7
     js main.chunk.js:905
     Webpack 7
 react-dom.utveckling.js:15162

Varför händer detta? React förlitar sig på den ordning i vilken krokarna anropas eftersom React inte skulle veta vad som ska returneras för useEffect eftersom det inte fanns någon sådan krok i raden att kontrollera.

Kom ihåg att eslint är ett kraftfullt verktyg som hjälper oss att hitta många potentiella buggar och fel. Att inaktivera dess varningar är en farlig sak, kontrollera alltid om ignorering av varningen kan orsaka en appkrasch.

användningStatus

Du vet säkert hur det ser ut 😉.

const [värde, setValue] = useState(0);

Så du har 4 element: tillstånd (reaktivt värde), uppdateringsfunktion (setter), faktisk krok (funktion) och valfritt initialt värde. Varför returnerar den en array? För att vi kan omstrukturera den som vi vill.

Nu vill jag fokusera på det sista elementet - det initiala värdet. Det finns två sätt att skicka det initiala tillståndet:

  1. Med hårdkodat värde eller liknande - som kommer att anropas vid varje rendering
const [värde, setValue] = useState(0);
  1. Genom en funktionsversion. Det är verkligen till stor hjälp om vi vill köra initialtillståndet bara en gång, vid den allra första renderingen. Kanske behöver du göra en massa komplexa beräkningar för att få det initiala tillståndet? Det kommer snyggt att minska resurskostnaden, yay!
const [value, setValue] = useState(() => {
   console.log("INIT");
   return 0;
 });

Hur kontrollerar jag att det första sättet verkligen anropas vid varje rendering? Skapa en funktion och skicka den som ett initialt tillstånd:

const checkInit = () => {
console.log("INIT");
return 0;
};

const [value, setValue] = useState(checkInit());
```

Och nu passerar du den på det andra sättet:

const checkInit = () => {
console.log("INIT");
return 0;
};

const [value, setValue] = useState(() => checkInit());
```

Coolt, eller hur?

noice.png

En annan sak som kan skapa buggar i appflödet: du vet säkert hur man uppdaterar ett tillstånd, eller hur?

setValue(1);

Okej... men vad händer om jag vill uppdatera statusen baserat på en tidigare status?

setValue(värde + 1);

Ja... Men nej... Tänk om du försöker anropa setter-funktionen två gånger, efter varandra? Det rekommenderade sättet att uppdatera ett tillstånd baserat på det föregående tillståndet är att använda en funktion. Det garanterar att du refererar till det tidigare tillståndet

setValue((prevState) => prevState + 1);
// med objekt:
setUser((prevState) => ({ ...prevState, efternamn: "Brzeczyszczykiewicz" }));

användaEffekt

Denna Hook tar 2 argument (det andra är valfritt) och vi använder det för att hantera bieffekter. Och beroende på vad vi skickar som ett andra argument kommer kroken att anropas på olika sätt:

  1. utan andra argument - varje rendering
användEffekt(() => {
   doSomething();
 });
  1. tom array - endast vid första renderingen
useEffect(() => {
   görnågot();
 }, []);
  1. matris med beroenden - varje gång värdet i beroendematrisen ändras
användEffekt(() => {
   görnågot(värde);
 }, [värde]);

Rengöring

Med useEffect kan vi använda något som kallas cleanup. Vad är det för något? Det är väldigt användbart, men jag tycker att det är bäst för att städa eventlyssnare. Låt oss säga att du vill skapa en händelselyssnare som beror på något tillstånd. Du vill inte lägga till en ny eventlyssnare vid varje tillståndsändring, för efter några renderingar kommer det att finnas så många lyssnare att det kommer att påverka appens prestanda. Ett bra sätt att undvika sådana saker är att använda uppstädningsfunktionen. Hur gör man det? Lägg bara till en returfunktion till useEffect.

useEffect(() => {
console.log("bieffekt 1", antal);
return () => {
console.log("DESTROYED 1");
};
});

useEffect(() => {
console.log("sidoeffekt 2", count);
return () => {
console.log("DESTROYED 2");
};
}, []);

useEffect(() => {
console.log("sidoeffekt 3", count);
return () => {
console.log("DESTROYED 3");
};
}, [count]);
```

Eftersom det är inuti useEffect Hook anropas returen beroende på beroendematrisen - vid varje rendering, endast vid den första renderingen eller när värdet i beroendematrisen ändras. Men när komponenten avmonteras kommer cleaning att anropas på det andra argumentet oavsett vad. Returnera kod anropas före den faktiska koden från Hook. Det är väldigt logiskt - först rensa den gamla, sedan skapa en ny. Eller hur?

användEffekt(() => {
   // addEventListener
   console.log("Lägg till");
   return () => {
     // ta bort händelseförvaltare
     console.log("Ta bort");
   };
 }, [värde]);

Så först kommer du att få en ta bort meddelande, då Lägg till.

Det finns en sak att vara uppmärksam på när man använder useEffect och asynkron kod inuti den. Ta en titt på koden nedan:

användEffekt(() => {
   fetch("https://picsum.photos/5000/5000").then() => {
     setValue((prevState) => prevState + 1);
   });
 }, []);

Till en början ser det ok ut. Du hämtar lite data, och när datan kommer uppdaterar du tillståndet. Och här är fällan:

Ibland kommer du att få en sådan varning:
Kan inte utföra en React-statusuppdatering på en omonterad komponent. Det här är inget alternativ, men det indikerar en minnesläcka i din applikation. För att åtgärda detta, avbryt alla prenumerationer och asynkrona uppgifter i en useEffect-rensningsfunktion.

Anledningen är att komponenten kan avmonteras under tiden, men appen kommer fortfarande att försöka uppdatera komponentens tillstånd efter att löftet har uppfyllts. Hur hanterar man det? Du måste kontrollera om komponenten finns.

useEffect(() => {
låt monterad = true;
fetch("https://picsum.photos/5000/5000").then() => {
if (monterad) {
setValue((prevState) => prevState + 1);
}
});

return () => {
monterad = falsk;
};
}, []);
```

Obs: Det finns en mycket liknande Hook => useLayoutEffect() - återuppringningen körs efter att komponenten har renderats men innan domänen uppdateras visuellt. Det är användbart när du arbetar med getBoundingClientRect(), men du bör använda useEffect som standard. Varför är det så? Eftersom det kan blockera visuella uppdateringar - när du har en komplex kod inuti din effekt Hook.

användaKontext

Vad är den till för? Delning av data utan att skicka props. Består av följande element:

  1. Skapat sammanhang - data
  2. Kontextleverantör - ger kontext till alla barn
  3. Överfört värde - data som du vill dela med dig av
  4. Hook - för att läsa delad data
const användare = {
namn: "Adam",
efternamn: "Kowalski",
};

export const UserContext = createContext(user);

;
```

I Child måste du importera kontexten och anropa useContext Hook och skicka kontexten som ett argument.

import { UserContext } från "./App";

const { namn } = useContext(UserContext);

retur <h1>Hej {namn}<>
```

Voilà. Ser coolt ut. Mestadels för att skicka globala data som teman etc. Rekommenderas inte för användning i uppgifter med mycket dynamiska ändringar.

Naturligtvis kan vi skapa en anpassad kontextleverantör och en anpassad krok för att minska boilerplate istället ... men jag kommer att ta itu med anpassade krokar i nästa artikel.

användReducer

Det gör att vi kan hantera tillståndet och återskapa när tillståndet ändras - som useState. Det liknar redux-reduceraren. Den här är bättre än useState när tillståndslogiken är mer komplicerad.

const [state, dispatch] = useReducer(reducer, initialArg); 
  • Returnerar aktuellt tillstånd med en sändningsmetod.
  • På ett annat sätt än i redux anges det initiala värdet när Hook anropas.

Det finns också ett tredje argument som kan skickas till useReducer - init-funktionen.

const [state, dispatch] = useReducer(reducer, initialArg, init);

Vad är den till för? Den kan användas när vi vill återställa tillståndet till dess ursprungliga värde. Nedan hittar du ett bra exempel:

// Förälder
// Barn
funktion init(initialNumber) {
return { number: initialNumber };
}

funktion reducer(tillstånd, åtgärd) {
switch (åtgärd.typ) {
fall "change":
return { antal: Math.random() };
fall "reset":
return init(åtgärd.nyttolast);
default:
throw new Error();
}
}

export default function ChildComponent({ getFactorial }) {
const [state, dispatch] = useReducer(reducer, initialNumber, init);

return (
<>
   <h2>Nummer: {stat.nummer}</h2>
      <button
        onclick="{()" > dispatch({ typ: "reset", nyttolast: initialNumber })}
      &gt;
        Återställ
      </button>
      <button onclick="{()" > dispatch({typ: "ändring" })}&gt;Dra</button>
    </>
  );
}

Nummer: {stat.nummer}

ReducerInit.png

användaCallback

När ska man använda det? När vi vill uppnå referentiell likhet (och därmed minska antalet skapade funktioner). Den här kroken returnerar funktionen, till skillnad från useMemo som returnerar värdet.

Exempel: Skapa en funktion i den överordnade komponenten och skicka den sedan via props

//// Förälder
 const getSquaredValue = () => count * count;
 ...
 return (
   )
 )

Kontrollera sedan i barnkomponenten hur många gånger effekten Hook kommer att anropas efter att funktionen har lagts till i beroendematrisen:

// Barn
 useEffect(() => {
   console.log("getSquaredValue", getSquaredValue());
 }, [getSquaredValue]);

Den kommer att logga till konsolen vid varje rendering! Även om värdena inuti getSquaredValue() funktionen ändrades inte. Men vi kan undvika detta genom att linda in den funktionen i useCallback

const getSquaredValue = useCallback(() => count * count, [count])

Vi kan också skicka några parametrar till den här funktionen:

const getSquaredValue = useCallback(
   (multiplikator) => räkna * räkna * multiplikator,
   [antal]
 );

användaMemo

const memoizedValue = useMemo(() => {
   return doSomething(värde);
 }, [värde]);
  • Det är inte neutralt när man tittar på kostnaderna för resurser - useMemo måste anropas vid varje rendering, sparar värdet i minnet och jämför (minnesoverhead),
  • använder Memoization - optimeringstekniken, specifik form av cachning.

Du bör endast använda den i två scenarier:

  1. Om du vill undvika att anropa en komplex kod vid varje rendering;
  2. Om du vill uppnå referentiell jämlikhet.

Låt oss titta lite närmare på det andra fallet. Vi vill använda useEffect med ett objekt som ett beroende. Eftersom objekt jämförs med sin referens kommer useEffect att anropas vid varje rendering. För att undvika sådana saker kan vi kombinera useEffect med useMemo för att memorera sådana objekt och sedan skicka de memorerade objekten till beroendematrisen. Kort exempel:

Första försöket att göra det utan useMemo:

const hobbit = { namn: "Bilbo" };

useEffect(() => {
console.log("Hello ", hobbit.name);
}, [hobbit]);
```

Du kommer också att få en varning:

Objektet "hobbit" gör att beroendena för useEffect Hook (rad 49) ändras vid varje rendering. Flytta in det i useEffect callback. Alternativt kan initialiseringen av 'hobbit' paketeras i sin egen useMemo () Hook.eslintreact-hooks/exhaustive-deps

Försök sedan med useMemo:

const hobbit = useMemo(() => {
return { namn: "Bilbo" };
}, []);

useEffect(() => {
console.log("Hello ", hobbit.name);
}, [hobbit]);
```

användningRef

Det viktigaste: useRef utlöser inte omrendering (som useState) eftersom den inte är kopplad till renderingscykeln - den behåller samma referens mellan renderingarna.

const ref = useRef(0);

Om du vill anropa det sparade värdet måste du använda en aktuell egenskap (ref är ett objekt) ref.nuvarande

Det andra fallet där vi kan använda den här kroken är för att referera till element i HTML. Varje element har ett ref-attribut. Så vi kan hantera fokus, händelser etc.

Det tredje fallet är att vi kan använda refs för att hantera okontrollerade komponenter. Du kan läsa mer om dem i React-dokument,
men i korthet ser det ut så här:

export default funktion OkontrolleradForm() {
  const input = useRef();

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(input.current.value);
  };

  return (
    
      
      Sänd
     </form
  );
}

Som du kan se finns det ingen händelsehanterare, den kommer bara ihåg det inskrivna värdet. Det är utmärkt för att hantera grundläggande formulär när du bara vill läsa sparade värden när du behöver dem (som när du skickar in).

Bonus: Det är bra när du behöver komma ihåg tidigare tillståndsvärden. Du kan använda useEffect Hook för det, bara skicka tillståndet till ref.

const [värde, setValue] = useState("");

let prevValue = useRef("");

useEffect(() => {
  prevValue.current = värde;
}, [värde]);

 setValue(e.target.value)}>;

Som du kan se är Hooks inte så uppenbara. Vi kan kombinera dem för att lösa många problem. Du kommer säkert att ha stor nytta av att studera detta ämne.

Och det finns också anpassade krokar...

Sammanfattningsvis, React krokar har revolutionerat sättet React utvecklare tillvägagångssätt byggnad webbapplikationer . Genom att tillhandahålla ett mer intuitivt och effektivt sätt att hantera tillstånd och livscykel i funktionella komponenter har krokar blivit en integrerad del av React utveckling .

Oavsett om du är en erfaren utvecklare eller precis har börjat med React är det viktigt att förstå de mest populära krokarna och deras användningsområden. Med krokar som useState, useEffect, useContext och mer, React-komponenter kan byggas med renare och mer återanvändbar kod. Dessutom är möjligheten att skapa anpassade krokar gör det möjligt för utvecklare att kapsla in och dela logik över flera komponenter, vilket främjar återanvändning av kod och modularitet. I takt med att React fortsätter att utvecklas och introducera nya funktioner kommer hooks utan tvekan att spela en central roll för att utnyttja ramverkets fulla potential.

Så oavsett om du arbetar med en liten funktionsapp eller en storskalig webbapplikation, är det viktigt att ta till sig React krokar kommer att förbättra ditt utvecklingsarbetsflöde och öppna upp en uppsjö av möjligheter för att skapa robusta och funktionsrika React-applikationer .

Slutet av del 1

Läs mer om detta:

JavaScript är helt död. Någon snubbe på internet

Distribuera GraphQL/MongoDB API med hjälp av Netlify-funktioner

Hur man dödar ett projekt med dålig kodningspraxis

Relaterade artiklar

Utveckling av programvara

Bygg framtidssäkrade webbappar: Insikter från The Codest:s expertteam

Upptäck hur The Codest utmärker sig genom att skapa skalbara, interaktiva webbapplikationer med banbrytande teknik som ger sömlösa användarupplevelser på alla plattformar. Läs om hur vår expertis driver digital omvandling och affärsutveckling...

DEKODEST
Utveckling av programvara

Topp 10 Lettlandsbaserade mjukvaruutvecklingsföretag

Läs mer om Lettlands främsta mjukvaruutvecklingsföretag och deras innovativa lösningar i vår senaste artikel. Upptäck hur dessa teknikledare kan hjälpa till att lyfta ditt företag.

thecodest
Lösningar för företag och uppskalningsföretag

Java Software Development Essentials: En guide till framgångsrik outsourcing

Utforska denna viktiga guide om framgångsrik outsourcing av Java-programvaruutveckling för att förbättra effektiviteten, få tillgång till expertis och driva projektframgång med The Codest.

thecodest
Utveckling av programvara

Den ultimata guiden till outsourcing i Polen

Den kraftiga ökningen av outsourcing i Polen drivs av ekonomiska, utbildningsmässiga och tekniska framsteg, vilket främjar IT-tillväxt och ett företagsvänligt klimat.

TheCodest
Lösningar för företag och uppskalningsföretag

Den kompletta guiden till verktyg och tekniker för IT-revision

IT-revisioner säkerställer säkra, effektiva och kompatibla system. Läs mer om hur viktiga de är genom att läsa hela artikeln.

Codest
Jakub Jakubowicz CTO och medgrundare

Prenumerera på vår kunskapsbas och håll dig uppdaterad om expertisen från IT-sektorn.

    Om oss

    The Codest - Internationellt mjukvaruutvecklingsföretag med teknikhubbar i Polen.

    Förenade kungariket - Huvudkontor

    • Kontor 303B, 182-184 High Street North E6 2JA
      London, England

    Polen - Lokala tekniknav

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Kraków
    • Brain Embassy, Konstruktorska
      11, 02-673 Warszawa, Polen

      Codest

    • Hem
    • Om oss
    • Tjänster
    • Fallstudier
    • Vet hur
    • Karriär
    • Ordbok

      Tjänster

    • Det rådgivande
    • Utveckling av programvara
    • Backend-utveckling
    • Frontend-utveckling
    • Staff Augmentation
    • Backend-utvecklare
    • Ingenjörer inom molntjänster
    • Dataingenjörer
    • Övriga
    • QA-ingenjörer

      Resurser

    • Fakta och myter om att samarbeta med en extern partner för mjukvaruutveckling
    • Från USA till Europa: Varför väljer amerikanska startup-företag att flytta till Europa?
    • Jämförelse av Tech Offshore Development Hubs: Tech Offshore Europa (Polen), ASEAN (Filippinerna), Eurasien (Turkiet)
    • Vilka är de största utmaningarna för CTO:er och CIO:er?
    • Codest
    • Codest
    • Codest
    • Privacy policy
    • Användarvillkor för webbplatsen

    Copyright © 2025 av The Codest. Alla rättigheter reserverade.

    sv_SESwedish
    en_USEnglish de_DEGerman da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek sv_SESwedish