window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster już istnieje') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() Dokładniejsze spojrzenie na najpopularniejsze haki React - The Codest
The Codest
  • O nas
  • Nasze Usługi
    • Software Development
      • Frontend Development
      • Backend Development
    • Zespoły IT
      • Programiści frontendowi
      • Backend Dev
      • Inżynierowie danych
      • Inżynierowie rozwiązań chmurowych
      • Inżynierowie QA
      • Inne
    • Konsultacje IT
      • Audyt i doradztwo
  • Branże
    • Fintech i bankowość
    • E-commerce
    • Adtech
    • Healthtech
    • Produkcja
    • Logistyka
    • Motoryzacja
    • IOT
  • Wartość dla
    • CEO
    • CTO
    • Delivery Managera
  • Nasz zespół
  • Case Studies
  • Nasze Know How
    • Blog
    • Meetups
    • Webinary
    • Raporty
Kariera Skontaktuj się z nami
  • O nas
  • Nasze Usługi
    • Software Development
      • Frontend Development
      • Backend Development
    • Zespoły IT
      • Programiści frontendowi
      • Backend Dev
      • Inżynierowie danych
      • Inżynierowie rozwiązań chmurowych
      • Inżynierowie QA
      • Inne
    • Konsultacje IT
      • Audyt i doradztwo
  • Wartość dla
    • CEO
    • CTO
    • Delivery Managera
  • Nasz zespół
  • Case Studies
  • Nasze Know How
    • Blog
    • Meetups
    • Webinary
    • Raporty
Kariera Skontaktuj się z nami
Strzałka w tył WSTECZ
2021-12-07
Software Development

Dokładniejsze spojrzenie na najpopularniejsze haki React

The Codest

Paweł Rybczyński

Software Engineer

W trakcie wielu rozmów zauważyłem, że nawet doświadczeni programiści mają problem z rozróżnieniem Hooków, nie wspominając już o ich bardziej zaawansowanych możliwościach. W tym artykule postaram się więc wyjaśnić, w jaki sposób Hooki powinny być wykorzystywane.

Najważniejsze rzeczy, które należy pamiętać o Hooks:

  • mogą być używane tylko w komponentach funkcyjnych - komponenty klasowe mają własną implementację cyklu życia;
  • zawsze zaczynają się od użycie;
  • Możesz używać dowolnej liczby haków, ale musisz pamiętać, że korzystanie z nich ma wpływ na ogólną wydajność;
  • muszą być wykonywane w tej samej kolejności przy każdym renderowaniu... ale dlaczego? Spójrzmy na przykład:
import { useState,useEffect } z "react";

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

return (
  <>
    <p>{`Pojedyncza ${wartość} Double ${doubleValue}`}</p>
    <button onclick="{()" > setValue(value + 1)}&gt;Check</button>
  </>
);
}
```

Na początku otrzymasz ostrzeżenie od eslint:

<code>srcFunctionComponent.js
   Linia 11:5: React Haczyk "useEffect" jest wywoływany warunkowo. <strong>React Haki</strong> muszą być wywoływane dokładnie w tej samej kolejności w każdym komponencie render .eslintreact-hooks/rules-of-hooks

Jak widać, jest to tylko ostrzeżenie eslint, więc można je wyłączyć, dodając polecenie od dołu na górze pliku FunctionComponent

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

i będzie działać, ale tylko do momentu spełnienia warunku, który uruchamia nasz Hook. Następną rzeczą, którą zobaczymy, jest ten błąd.

Niewykryty błąd: Wyrenderowano więcej haków niż podczas poprzedniego renderowania.
     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

Dlaczego tak się dzieje? React polega na kolejności wywoływania haków, ponieważ React nie wiedziałby, co zwrócić dla useEffect, ponieważ nie było takiego haka w linii do sprawdzenia.

Pamiętaj, że eslint to potężne narzędzie, które pomaga nam wyłapać wiele potencjalnych błędów. Wyłączenie jego ostrzeżeń jest niebezpieczne, zawsze sprawdzaj, czy zignorowanie ostrzeżenia może spowodować awarię aplikacji.

useState

Pewnie wiesz jak to wygląda 😉

const [value, setValue] = useState(0);

Mamy więc 4 elementy: stan (wartość reaktywna), funkcja aktualizacji (setter), rzeczywisty hak (funkcja) i opcjonalna wartość początkowa. Dlaczego zwraca tablicę? Ponieważ możemy ją dowolnie restrukturyzować.

Teraz chciałbym skupić się na ostatnim elemencie - wartości początkowej. Istnieją dwa sposoby przekazania stanu początkowego:

  1. Przez zakodowaną wartość lub coś innego - co będzie wywoływane przy każdym renderowaniu
const [value, setValue] = useState(0);
  1. Przez wersję funkcji. Jest to bardzo pomocne, jeśli chcemy uruchomić stan początkowy tylko raz, przy pierwszym renderowaniu. Może trzeba wykonać wiele skomplikowanych obliczeń, aby otrzymać stan początkowy? To ładnie zmniejszy koszt zasobów, yay!
const [value, setValue] = useState(() => {
   console.log("INIT");
   return 0;
 });

Jak sprawdzić, czy pierwszy sposób jest rzeczywiście wywoływany przy każdym renderowaniu? Utwórz funkcję i przekaż ją jako stan początkowy:

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

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

A teraz przekaż go za pomocą drugiego sposobu:

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

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

Fajnie, prawda?

noice.png

Kolejna rzecz, która może powodować błędy w przepływie aplikacji: prawdopodobnie wiesz, jak zaktualizować stan, prawda?

setValue(1);

Racja... ale co jeśli chcę zaktualizować stan na podstawie poprzedniego stanu?

setValue(value + 1);

Tak... Ale nie... Co jeśli spróbujesz wywołać funkcję setter dwa razy, jeden po drugim? Zalecanym sposobem aktualizacji stanu na podstawie poprzedniego stanu jest użycie funkcji. Gwarantuje to, że odwołujesz się do poprzedniego stanu

setValue((prevState) => prevState + 1);
// z obiektami:
setUser((prevState) => ({ ...prevState, lastName: "Brzeczyszczykiewicz" }));

useEffect

Ten hak przyjmuje 2 argumenty (drugi jest opcjonalny) i używamy go do obsługi efektów ubocznych. W zależności od tego, co przekażemy jako drugi argument, hak zostanie wywołany inaczej:

  1. bez drugiego argumentu - każdy render
useEffect(() => {
   doSomething();
 });
  1. pusta tablica - tylko przy pierwszym renderowaniu
useEffect(() => {
   doSomething();
 }, []);
  1. tablica z zależnościami - za każdym razem, gdy zmienia się wartość w tablicy zależności
useEffect(() => {
   doSomething(value);
 }, [value]);

Czyszczenie

Dzięki useEffect możemy użyć czegoś, co nazywa się cleanup. Do czego to służy? Jest to bardzo przydatne, ale myślę, że najlepiej nadaje się do czyszczenia detektorów zdarzeń. Załóżmy, że chcemy stworzyć event listener, który zależy od jakiegoś stanu. Nie chcesz dodawać nowego detektora zdarzeń przy każdej zmianie stanu, ponieważ po kilku renderowaniach będzie tak wiele detektorów, że wpłynie to na wydajność aplikacji. Świetnym sposobem na uniknięcie takich rzeczy jest użycie funkcji czyszczenia. Jak to zrobić? Wystarczy dodać funkcję zwrotną do useEffect.

useEffect(() => {
console.log("efekt uboczny 1", count);
return () => {
console.log("ZNISZCZONO 1");
};
});

useEffect(() => {
console.log("efekt uboczny 2", count);
return () => {
console.log("ZNISZCZONO 2");
};
}, []);

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

Ponieważ jest to wewnątrz haka useEffect, zwracanie jest wywoływane w zależności od tablicy zależności - przy każdym renderowaniu, tylko przy pierwszym renderowaniu lub gdy zmienia się wartość w tablicy zależności. Ale kiedy komponent zostanie odmontowany, czyszczenie zostanie wywołane na drugim argumencie bez względu na wszystko. Zwrot kod jest wywoływana przed właściwym kodem z Hook. To bardzo logiczne - najpierw wyczyść stary, a następnie utwórz nowy. Prawda?

useEffect(() => {
   // addEventListener
   console.log("Dodaj");
   return () => {
     // removeEventListener
     console.log("Remove");
   };
 }, [value]);

Po pierwsze, otrzymasz usunąć wiadomość, a następnie Dodaj.

Jest jedna rzecz, na którą należy zwrócić uwagę podczas korzystania z useEffect i kodu asynchronicznego wewnątrz niego. Spójrz na poniższy kod:

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

Na początku wygląda to dobrze. Pobierasz jakieś dane, a gdy dane nadejdą, aktualizujesz stan. I tu jest pułapka:

Czasami otrzymasz takie ostrzeżenie:
Nie można wykonać aktualizacji stanu React na niezamontowanym komponencie. Jest to sytuacja bezczynności, ale wskazuje na wyciek pamięci w aplikacji. Aby to naprawić, anuluj wszystkie subskrypcje i zadania asynchroniczne w funkcji czyszczenia useEffect.

Powodem jest to, że komponent może zostać odmontowany w międzyczasie, ale aplikacja nadal będzie próbowała zaktualizować stan tego komponentu po spełnieniu obietnicy. Jak sobie z tym poradzić? Należy sprawdzić, czy komponent istnieje.

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

return () => {
mounted = false;
};
}, []);
```

Uwaga: Istnieje bardzo podobny Hook => useLayoutEffect() - wywołanie zwrotne działa po wyrenderowaniu komponentu, ale przed wizualną aktualizacją domeny. Jest to przydatne podczas pracy z getBoundingClientRect(), ale domyślnie powinieneś używać useEffect. Dlaczego? Ponieważ może blokować aktualizacje wizualne - gdy masz złożony kod wewnątrz efektu Hook.

useContext

Do czego to służy? Udostępnianie danych bez przekazywania rekwizytów. Składa się z następujących elementów:

  1. Utworzony kontekst - dane
  2. Dostawca kontekstu - zapewnia kontekst wszystkim dzieciom
  3. Przekazana wartość - dane, które chcesz udostępnić
  4. Hook - do odczytu udostępnionych danych
const user = {
name: "Adam",
lastName: "Kowalski",
};

export const UserContext = createContext(user);

;
```

W child należy zaimportować kontekst, wywołać hak useContext i przekazać ten kontekst jako argument.

import { UserContext } z "./App";

const { name } = useContext(UserContext);

return <h1>Cześć {imię}<>
```

Voila. Wygląda fajnie. Głównie do przekazywania danych globalnych, takich jak motywy itp. Nie zaleca się używania w zadaniach z bardzo dynamicznymi zmianami.

Oczywiście możemy utworzyć niestandardowego dostawcę kontekstu i niestandardowy hak, aby zamiast tego zredukować boilerplate... ale niestandardowymi hakami zajmę się w następnym artykule.

useReducer

Pozwala nam zarządzać stanem i ponownie renderować, gdy stan się zmieni - jak useState. Jest podobny do reduktora redux. Jest to lepsze rozwiązanie niż useState, gdy logika stanu jest bardziej skomplikowana.

const [state, dispatch] = useReducer(reducer, initialArg); 
  • Zwraca aktualny stan za pomocą metody wysyłki.
  • Inaczej niż w redux, wartość początkowa jest określana w momencie wywołania haka.

Istnieje również trzeci argument, który można przekazać do useReducer - funkcja init.

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

Do czego służy? Można go użyć, gdy chcemy zresetować stan do wartości początkowej. Poniżej znajduje się ładny przykład:

// Rodzic
// Dziecko
function init(initialNumber) {
return { number: initialNumber };
}

function reducer(state, action) {
switch (action.type) {
case "change":
return { number: Math.random() };
case "reset":
return init(action.payload);
default:
throw new Error();
}
}

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

return (
<>
   <h2>Numer: {state.number}</h2>
      <button
        onclick="{()" > dispatch({ type: "reset", payload: initialNumber })}
      &gt;
        Reset
      </button>
      <button onclick="{()" > dispatch({ type: "change" })}&gt;Draw</button>
    </>
  );
}

Numer: {state.number}

ReducerInit.png

useCallback

Kiedy go używać? Gdy chcemy osiągnąć równość referencyjną (zmniejszając tym samym liczbę tworzonych funkcji). Hook ten zwraca funkcję, w przeciwieństwie do useMemo, który zwraca wartość.

Przykład: Utwórz funkcję w komponencie nadrzędnym, a następnie przekaż ją za pośrednictwem rekwizytów

// Parent
 const getSquaredValue = () => count * count;
 ...
 return (
   )
 )

Następnie sprawdź w komponencie potomnym, ile razy efekt Hook zostanie wywołany po dodaniu tej funkcji do tablicy zależności:

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

Będzie logować się do konsoli przy każdym renderowaniu! Nawet jeśli wartości wewnątrz getSquaredValue() nie uległa zmianie. Możemy jednak tego uniknąć, opakowując tę funkcję w useCallback

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

Możemy również przekazać kilka parametrów do tej funkcji:

const getSquaredValue = useCallback(
   (mnożnik) => count * count * mnożnik,
   [count]
 );

useMemo

const memoizedValue = useMemo(() => {
   return doSomething(value);
 }, [value]);
  • Nie jest to neutralne patrząc na koszty zasobów - useMemo musi być wywoływane przy każdym renderowaniu, zapisuje wartość w pamięci i porównuje (narzut pamięci),
  • wykorzystuje Memoization - technikę optymalizacji, specyficzną formę buforowania.

Powinieneś go używać tylko w 2 scenariuszach:

  1. Jeśli chcesz uniknąć wywoływania złożonego kodu przy każdym renderowaniu;
  2. Jeśli chcesz osiągnąć równość referencyjną.

Przyjrzyjmy się nieco bliżej drugiemu przypadkowi. Chcemy użyć useEffect z obiektem jako zależnością. Ponieważ obiekty są porównywane przez referencję, useEffect będzie wywoływane przy każdym renderowaniu. Aby tego uniknąć, możemy połączyć useEffect z useMemo, aby zapamiętać takie obiekty, a następnie przekazać zapamiętane obiekty do tablicy zależności. Krótki przykład:

Najpierw spróbuj zrobić to bez useMemo:

const hobbit = { name: "Bilbo" };

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

Otrzymasz również ostrzeżenie:

Obiekt "hobbit" sprawia, że zależności haka useEffect (linia 49) zmieniają się przy każdym renderowaniu. Przenieś go wewnątrz wywołania zwrotnego useEffect. Alternatywnie, zawiń inicjalizację "hobbita" w jego własny hak useMemo ().eslintreact-hooks/exhaustive-deps

Następnie spróbuj z useMemo:

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

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

useRef

Najważniejsza rzecz: useRef nie wywołuje ponownego renderowania (jak useState), ponieważ nie jest powiązany z cyklem renderowania - zachowuje tę samą referencję między renderowaniami.

const ref = useRef(0);

Aby wywołać zapisaną wartość, należy użyć właściwości current (ref jest obiektem) - ref.current

Drugim przypadkiem, w którym możemy użyć tego haka, jest odniesienie do elementów wewnątrz HTML. Każdy element ma atrybut ref. Możemy więc obsługiwać fokus, zdarzenia itp.

Trzecim przypadkiem jest użycie referencji do obsługi niekontrolowanych komponentów. Więcej na ich temat można przeczytać w dokumenty react,
ale w skrócie wygląda to tak:

export default function UncontrolledForm() {
  const input = useRef();

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

  return (
    
      
      
    
  );
}

Jak widać, nie ma obsługi zdarzeń, po prostu zapamiętuje wpisaną wartość. Świetnie nadaje się do obsługi podstawowych formularzy, gdy chcesz po prostu odczytać zapisane wartości, gdy ich potrzebujesz (np. podczas wysyłania).

Bonus: Jest to świetne rozwiązanie, gdy trzeba zapamiętać poprzednie wartości stanu. Możesz użyć do tego haka useEffect, po prostu przekaż stan do ref.

const [value, setValue] = useState("");

let prevValue = useRef("");

useEffect(() => {
  prevValue.current = value;
}, [value]);

 setValue(e.target.value)}>;

Jak widać, haki nie są takie oczywiste. Możemy je łączyć, aby rozwiązać wiele problemów. Zapoznanie się z tym tematem z pewnością przyniesie wiele korzyści.

Istnieją również niestandardowe haki...

Podsumowując, Haki React zrewolucjonizowały sposób Programiści React budowanie podejścia aplikacje internetowe . Zapewniając bardziej intuicyjny i wydajny sposób zarządzania stanem i cyklem życia w komponentach funkcjonalnych, haki stały się integralną częścią Rozwój React .

Niezależnie od tego, czy jesteś doświadczonym programistą, czy dopiero zaczynasz pracę z React, zrozumienie najpopularniejszych haków i ich przypadków użycia ma kluczowe znaczenie. Z hakami takimi jak useState, useEffect, useContext i nie tylko, Komponenty React może być zbudowany z czystszego i bardziej wielokrotnego użytku kodu. Co więcej, możliwość tworzenia niestandardowe haki umożliwia programistom hermetyzację i współdzielenie logiki w wielu komponentach, promując ponowne wykorzystanie kodu i modułowość. Ponieważ React nadal ewoluuje i wprowadza nowe funkcje, haki niewątpliwie odegrają kluczową rolę w wykorzystaniu pełnego potencjału frameworka.

Tak więc, niezależnie od tego, czy pracujesz nad małą aplikacją funkcyjną, czy dużą aplikacją internetową, przyjęcie Haki React usprawni przepływ pracy programisty i odblokuje mnóstwo możliwości tworzenia solidnych i bogatych w funkcje aplikacji. Zastosowania React .

Koniec części 1

Czytaj więcej:

JavaScript jest całkowicie martwy. Jakiś koleś w internecie

Wdrażanie API GraphQL/MongoDB przy użyciu funkcji Netlify

Jak zabić projekt złymi praktykami kodowania?

Powiązane artykuły

Software Development

Tworzenie przyszłościowych aplikacji internetowych: spostrzeżenia zespołu ekspertów The Codest

Odkryj, w jaki sposób The Codest wyróżnia się w tworzeniu skalowalnych, interaktywnych aplikacji internetowych przy użyciu najnowocześniejszych technologii, zapewniając płynne doświadczenia użytkowników na wszystkich platformach. Dowiedz się, w jaki sposób nasza wiedza napędza transformację cyfrową i biznes...

THEECODEST
Software Development

10 najlepszych firm tworzących oprogramowanie na Łotwie

Dowiedz się więcej o najlepszych łotewskich firmach programistycznych i ich innowacyjnych rozwiązaniach w naszym najnowszym artykule. Odkryj, w jaki sposób ci liderzy technologiczni mogą pomóc w rozwoju Twojej firmy.

thecodest
Rozwiązania dla przedsiębiorstw i scaleupów

Podstawy tworzenia oprogramowania Java: Przewodnik po skutecznym outsourcingu

Zapoznaj się z tym niezbędnym przewodnikiem na temat skutecznego tworzenia oprogramowania Java outsourcing, aby zwiększyć wydajność, uzyskać dostęp do wiedzy specjalistycznej i osiągnąć sukces projektu z The Codest.

thecodest
Software Development

Kompletny przewodnik po outsourcingu w Polsce

Wzrost liczby outsourcing w Polsce jest napędzany przez postęp gospodarczy, edukacyjny i technologiczny, sprzyjający rozwojowi IT i przyjazny klimat dla biznesu.

TheCodest
Rozwiązania dla przedsiębiorstw i scaleupów

Kompletny przewodnik po narzędziach i technikach audytu IT

Audyty IT zapewniają bezpieczne, wydajne i zgodne z przepisami systemy. Dowiedz się więcej o ich znaczeniu, czytając cały artykuł.

The Codest
Jakub Jakubowicz CTO & Współzałożyciel

Subskrybuj naszą bazę wiedzy i bądź na bieżąco!

    O nas

    The Codest - Międzynarodowa firma programistyczna z centrami technologicznymi w Polsce.

    Wielka Brytania - siedziba główna

    • Office 303B, 182-184 High Street North E6 2JA
      Londyn, Anglia

    Polska - lokalne centra technologiczne

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

      The Codest

    • Strona główna
    • O nas
    • Nasze Usługi
    • Case Studies
    • Nasze Know How
    • Kariera
    • Słownik

      Nasze Usługi

    • Konsultacje IT
    • Software Development
    • Backend Development
    • Frontend Development
    • Zespoły IT
    • Backend Dev
    • Inżynierowie rozwiązań chmurowych
    • Inżynierowie danych
    • Inne
    • Inżynierowie QA

      Raporty

    • Fakty i mity na temat współpracy z zewnętrznym partnerem programistycznym
    • Z USA do Europy: Dlaczego amerykańskie startupy decydują się na relokację do Europy?
    • Porównanie centrów rozwoju Tech Offshore: Tech Offshore Europa (Polska), ASEAN (Filipiny), Eurazja (Turcja)
    • Jakie są największe wyzwania CTO i CIO?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Warunki korzystania z witryny

    Copyright © 2025 by The Codest. Wszelkie prawa zastrzeżone.

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