Flutter vs. Dart
De fleste mennesker blander Flutter og Dart sammen, som om de er den samme ting, især fordi Dart og Flutter arbejder tæt sammen i udvikling på tværs af platforme. Begge er vigtige for at bygge android...
I løbet af mange interviews har jeg bemærket, at selv erfarne programmører har problemer med at skelne mellem Hooks, for slet ikke at tale om deres mere avancerede muligheder. Derfor vil jeg i denne artikel forsøge at forklare, hvordan Hooks skal bruges.
De vigtigste ting, du skal huske om Hooks:
brug;import { useState,useEffect } fra "reagere";
export default function FunctionComponent() {
const [value, setValue] = useState(1);
const [doubleValue, setDoubleValue] = useState(1);
if (værdi > 3) {
useEffect(() => setDoubleValue(value * 2),[value]);
}
return (
{`Enkelt ${værdi} Dobbelt ${dobbeltVærdi}`}
);
}
```
I første omgang får du en advarsel fra eslint:
<code>srcFunctionComponent.js
Linje 11:5: React Krog "useEffect" kaldes betinget. <strong>React-kroge</strong> skal kaldes i nøjagtig samme rækkefølge i hver komponent render .eslintreact-hooks/rules-of-hooks.
Som du kan se, er det kun en eslint-advarsel, så du kan deaktivere den ved at tilføje en kommando nedenunder i toppen af filen Funktionskomponent
/* eslint-disable react-hooks/rules-of-hooks */ .
og det vil virke, men kun indtil vi opfylder den betingelse, der kører vores Hook. Den næste ting, vi vil se, er denne fejl.

Uopdaget fejl: Renderede flere kroge end under den forrige rendering.
React 5
FunctionComponent FunctionComponent.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.development.js:15162
Hvorfor sker dette? React er afhængig af den rækkefølge, krogene kaldes i, da React ikke ville vide, hvad der skulle returneres for useEffect, fordi der ikke var en sådan krog i linjen at tjekke.
Husk, at eslint er et stærkt værktøj, det hjælper os fanger en masse potentielle bugs og fejl. Det er farligt at slå advarsler fra. Tjek altid, om det kan få appen til at gå ned, hvis du ignorerer advarslen.
Du ved sikkert, hvordan det ser ud 😉.
const [value, setValue] = useState(0);.
Så du har 4 elementer: tilstand (reaktiv værdi), opdateringsfunktion (setter), faktisk hook (funktion) og valgfri startværdi. Hvorfor returnerer den et array? Fordi vi kan omstrukturere det, som vi vil.
Nu vil jeg fokusere på det sidste element - den oprindelige værdi. Der er to måder at videregive den oprindelige tilstand på:
const [value, setValue] = useState(0);.
const [value, setValue] = useState(() => {
console.log("INIT");
return 0;
});
Hvordan kontrollerer jeg, at den første måde virkelig kaldes ved hver gengivelse? Opret en funktion, og send den som en indledende tilstand:
const checkInit = () => {
console.log("INIT");
return 0;
};
const [value, setValue] = useState(checkInit());
```
Og send den nu videre på den anden måde:
const checkInit = () => {
console.log("INIT");
return 0;
};
const [value, setValue] = useState(() => checkInit());
```
Sejt, ikke?

En anden ting, der kan skabe fejl i app-flowet: Du ved sikkert, hvordan man opdaterer en tilstand, ikke?
setValue(1);.
Ja ... men hvad nu, hvis jeg vil opdatere tilstanden ud fra en tidligere tilstand?
setValue(værdi + 1);.
Ja... Men nej... Hvad nu, hvis du prøver at kalde setter-funktionen to gange, den ene efter den anden? Den anbefalede måde at opdatere en tilstand på, baseret på den tidligere tilstand, er at bruge en funktion. Det garanterer, at du henviser til den tidligere tilstand
setValue((prevState) => prevState + 1);
// med objekter:
setUser((prevState) => ({ ...prevState, efternavn: "Brzeczyszczykiewicz" }));
Denne krog tager 2 argumenter (det andet er valgfrit), og vi bruger den til at håndtere bivirkninger. Og afhængigt af, hvad vi sender som det andet argument, vil krogen blive kaldt forskelligt:
useEffect(() => {
gørnoget();
});.
useEffect(() => {
gørnoget();
}, []);
useEffect(() => {
doSomething(værdi);
}, [værdi]);.
Med useEffect kan vi bruge noget, der kaldes cleanup. Hvad kan man bruge det til? Det er meget nyttigt, men jeg synes, det er bedst til at rense event-lyttere. Lad os sige, at du vil oprette en event-lytter, som afhænger af en eller anden tilstand. Du ønsker ikke at tilføje en ny event-lytter ved hver tilstandsændring, for efter nogle få renderinger vil der være så mange lyttere, at det vil påvirke appens ydeevne. En god måde at undgå sådanne ting på er at bruge oprydningsfunktionen. Hvordan gør man det? Du skal bare tilføje en returfunktion til useEffect.
useEffect(() => {
console.log("bivirkning 1", count);
return () => {
console.log("DESTROYED 1");
};
});
useEffect(() => {
console.log("bivirkning 2", count);
return () => {
console.log("DESTROYED 2");
};
}, []);
useEffect(() => {
console.log("bivirkning 3", count);
return () => {
console.log("DESTROYED 3");
};
}, [count]);
```
Fordi det er inde i useEffect Hook, kaldes return afhængigt af dependency array - ved hver rendering, kun ved den første rendering, eller når værdien i dependency array ændres. Men når komponenten afmonteres, vil cleaning blive kaldt på det andet argument uanset hvad. Returneringen Kode kaldes før den egentlige kode fra Hook. Det er meget logisk - først renser du den gamle, så opretter du en ny. Er det ikke rigtigt?
useEffect(() => {
// addEventListener
console.log("Tilføj");
return () => {
// fjernEventListener
console.log("Fjern");
};
}, [value]);.
Så først vil du modtage en fjerne besked, så Tilføj.
Der er én ting, man skal være opmærksom på, når man bruger useEffect og asynkron kode indeni. Se på koden nedenfor:
useEffect(() => {
fetch("https://picsum.photos/5000/5000").then(() => {
setValue((prevState) => prevState + 1);
});
}, []);.
Til at begynde med ser det ok ud. Du henter nogle dataog når dataene kommer, skal du opdatere tilstanden. Og her er fælden:
Nogle gange vil du modtage en sådan advarsel:Kan ikke udføre en React-tilstandsopdatering på en afmonteret komponent. Dette er en no-op, men det indikerer en hukommelseslækage i din applikation. Det kan løses ved at annullere alle abonnementer og asynkrone opgaver i en useEffect-oprydningsfunktion.
Årsagen er, at komponenten kan afmonteres i mellemtiden, men appen vil stadig forsøge at opdatere komponentens tilstand, efter at løftet er opfyldt. Hvordan håndterer man det? Du skal tjekke, om komponenten findes.
useEffect(() => {
let mounted = true;
fetch("https://picsum.photos/5000/5000").then(() => {
if (mounted) {
setValue((prevState) => prevState + 1);
}
});
return () => {
monteret = falsk;
};
}, []);
```
Bemærk: Der findes en meget lignende krog => useLayoutEffect() - tilbagekaldet kører efter rendering af komponenten, men før dom'en opdateres visuelt. Det er nyttigt, når du arbejder med getBoundingClientRect(), men du bør bruge useEffect som standard. Hvorfor det? Fordi det kan blokere visuelle opdateringer - når du har en kompleks kode inde i din effekt Hook.
Hvad kan man bruge det til? Deling af data uden at sende props. Består af følgende elementer:
const bruger = {
navn: "Adam",
efternavn: "Kowalski",
};
export const UserContext = createContext(user);
;
```
I child skal du importere konteksten og kalde useContext Hook og sende konteksten som et argument.
import { UserContext } fra "./App";
const { navn } = useContext(UserContext);
return <h1>Hej {navn}<>
```
Voilà. Det ser fedt ud. Mest til overførsel af globale data som temaer osv. Anbefales ikke til brug i opgaver med meget dynamiske ændringer.
Vi kan selvfølgelig oprette en brugerdefineret kontekstudbyder og en brugerdefineret krog for at reducere boilerplate i stedet ... men jeg vil beskæftige mig med brugerdefinerede kroge i den næste artikel.
Det giver os mulighed for at styre tilstanden og gengive den, når den ændrer sig - ligesom useState. Det svarer til Reduktion reducer. Denne er bedre end useState, når tilstandslogikken er mere kompliceret.
const [state, dispatch] = useReducer(reducer, initialArg); .
Der er også et tredje argument, som kan sendes til useReducer - init-funktionen.
const [state, dispatch] = useReducer(reducer, initialArg, init);.
Hvad kan man bruge den til? Den kan bruges, når vi vil nulstille tilstanden til dens oprindelige værdi. Nedenfor kan du se et godt eksempel:
// Forælder
// Barn
funktion init(initialNumber) {
return { number: initialNumber };
}
function reducer(state, action) {
switch (action.type) {
tilfælde "change":
return { number: Math.random() };
case "reset":
return init(action.payload);
standard:
throw new Error();
}
}
export default function ChildComponent({ getFactorial }) {
const [state, dispatch] = useReducer(reducer, initialNumber, init);
return (
<>
<h2>Nummer: {state.number}</h2>
<button
onclick="{()" > dispatch({ type: "reset", payload: initialNumber })}.
>
Nulstil
</button>
<button onclick="{()" > dispatch({ type: "change" })}>Tegne</button>
</>
);
}

Hvornår skal man bruge det? Når vi ønsker at opnå referentiel lighed (og dermed reducere antallet af oprettede funktioner). Denne krog returnerer funktionen, i modsætning til useMemo, som returnerer værdien.
Eksempel: Opret en funktion i den overordnede komponent, og send den derefter via props
// Parent
const getSquaredValue = () => count * count;
...
return (
).
Tjek derefter i den underordnede komponent, hvor mange gange effekten Hook vil blive kaldt efter tilføjelse af funktionen til afhængighedsarrayet:
// Barn
useEffect(() => {
console.log("getSquaredValue", getSquaredValue());
}, [getSquaredValue]);.
Den vil logge på konsollen ved hver gengivelse! Selv hvis værdierne inde i getSquaredValue() funktion blev ikke ændret. Men vi kan undgå dette ved at pakke funktionen ind i useCallback
const getSquaredValue = useCallback(() => count * count, [count]).
Vi kan også sende nogle parametre til denne funktion:
const getSquaredValue = useCallback(
(multiplikator) => tæller * tæller * multiplikator,
[count]
);.
const memoizedValue = useMemo(() => {
return doSomething(value);
}, [værdi]);.
Du bør kun bruge den i to scenarier:
Lad os se lidt nærmere på det andet tilfælde. Vi vil bruge useEffect med et objekt som en afhængighed. Da objekter sammenlignes ved hjælp af deres reference, vil useEffect blive kaldt ved hver gengivelse. For at undgå den slags kan vi kombinere useEffect med useMemo for at memorere sådanne objekter og derefter sende de memorerede objekter til dependency-arrayet. Et kort eksempel:
Prøv først at gøre det uden useMemo:
const hobbit = { navn: "Bilbo" };
useEffect(() => {
console.log("Hello ", hobbit.name);
}, [hobbit]);
```
Du vil også modtage en advarsel:
Objektet 'hobbit' får afhængighederne af useEffect-krogen (linje 49) til at ændre sig ved hver rendering. Flyt det ind i useEffect-tilbagekaldet. Alternativt kan du pakke initialiseringen af 'hobbit' ind i sin egen useMemo ()-krog.eslintreact-hooks/exhaustive-deps
Så prøv med useMemo:
const hobbit = useMemo(() => {
return { name: "Bilbo" };
}, []);
useEffect(() => {
console.log("Hello ", hobbit.name);
}, [hobbit]);
```
Den vigtigste ting: useRef udløser ikke genrendering (som useState), fordi den ikke er forbundet med renderingscyklussen - den beholder den samme reference mellem renderinger.
const ref = useRef(0);.
For at kalde den gemte værdi skal du bruge en aktuel egenskab (ref er et objekt) -. ref.nuværende
Det andet tilfælde, hvor vi kan bruge denne krog, er til at henvise til elementer i HTML. Hvert element har en ref-attribut. Så vi kan håndtere fokus, begivenheder osv.
Det tredje tilfælde er, at vi kan bruge refs til at håndtere ukontrollerede komponenter. Du kan læse mere om dem i react-dokumenter,
Men kort fortalt ser det sådan her ud:
export default function UncontrolledForm() {
const input = useRef();
const handleSubmit = (e) => {
e.preventDefault();
console.log(input.current.value);
};
return (
Send.
);
}
Som du kan se, er der ingen eventhandler, den husker bare den indtastede værdi. Det er godt til at håndtere grundlæggende formularer, hvor du bare vil læse gemte værdier, når du har brug for dem (f.eks. ved indsendelse).
Bonus: Det er fantastisk, når du har brug for at huske tidligere tilstandsværdier. Du kan bruge useEffect-krogen til det, bare send tilstanden til ref.
const [value, setValue] = useState("");
let prevValue = useRef("");
useEffect(() => {
prevValue.current = værdi;
}, [værdi]);
setValue(e.target.value)}>;
Som du kan se, er Hooks ikke så indlysende. Vi kan kombinere dem til at løse mange problemer. Du vil helt sikkert få stor gavn af at studere dette emne.
Og der er også brugerdefinerede kroge ...
Afslutningsvis, React-kroge har revolutioneret den måde React-udviklere tilgang til bygning web Applikationer . Ved at give en mere intuitiv og effektiv måde at styre tilstand og livscyklus på i funktionelle komponenter er hooks blevet en integreret del af React udvikling .
Uanset om du er en erfaren udvikler eller lige er startet med React, er det afgørende at forstå de mest populære hooks og deres anvendelsesmuligheder. Med hooks som useState, useEffect, useContext m.fl, React-komponenter kan bygges med renere og mere genanvendelig kode. Desuden er muligheden for at skabe Tilpassede kroge gør det muligt for udviklere at indkapsle og dele logik på tværs af flere komponenter, hvilket fremmer genanvendelighed og modularitet i koden. Efterhånden som React fortsætter med at udvikle sig og introducere nye funktioner, vil hooks utvivlsomt spille en central rolle i udnyttelsen af rammens fulde potentiale.
Så uanset om du arbejder på en lille funktionsapplikation eller en storstilet webapplikation, er det vigtigt at omfavne React-kroge vil forbedre dit udviklingsworkflow og åbne op for et væld af muligheder for at skabe robuste og funktionsrige React-applikationer .
Slut på del 1
Læs mere om det:
JavaScript er fuldstændig død. En fyr på internettet
Implementer GraphQL/MongoDB API ved hjælp af Netlify-funktioner