Najlepsze praktyki z hakami React

Opublikowany: 2022-03-10
Krótkie podsumowanie ↬ W tym artykule omówiono zasady React Hooks i jak skutecznie zacząć ich używać w swoich projektach. Pamiętaj, że aby szczegółowo zapoznać się z tym artykułem, musisz wiedzieć, jak korzystać z haków reakcji.

React Hooki to nowy dodatek w React 16.8, który pozwala używać stanu i innych funkcji Reacta bez pisania komponentu class . Innymi słowy, hooki to funkcje, które pozwalają „zahaczyć się” o funkcje stanu React i cyklu życia z komponentów funkcyjnych. (Nie działają wewnątrz komponentów class .)

React udostępnia kilka wbudowanych hooków, takich jak useState . Możesz także stworzyć własne hooki, aby ponownie wykorzystać zachowanie stanowe pomiędzy różnymi komponentami. Poniższy przykład pokazuje licznik, którego stan jest zarządzany za pomocą useState() . Za każdym razem, gdy klikniesz na przycisk, używamy setCount() do aktualizacji wartości count o 1 .

Zobacz Pen [przykład React Hook z licznikiem](https://codepen.io/smashingmag/pen/QWbXMyM) autorstwa Adeneye Abiodun David.

Zobacz przykład Pen React Hook z Counter autorstwa Adeneye Abiodun David.

Ten przykład renderuje licznik o wartości 0 . Kliknięcie przycisku powoduje zwiększenie wartości o 1 . Wartość początkowa składnika jest definiowana za pomocą useState .

 const [count, setCount] = useState(0)

Jak widać, ustawiliśmy to na 0 . Następnie używamy metody onClick() , aby wywołać setCount , gdy chcemy zwiększyć wartość.

 <button onClick={() => setCount(count + 1)}> Click me </button>

Przed wydaniem haków reakcji w tym przykładzie używano by więcej linii kodu, ponieważ musielibyśmy użyć komponentu class .

Więcej po skoku! Kontynuuj czytanie poniżej ↓

Zasady haków reakcyjnych

Zanim zagłębimy się w najlepsze praktyki, musimy zrozumieć zasady React Hooks, które są również jednymi z podstawowych koncepcji praktyk przedstawionych w tym artykule.

Hooki React są funkcjami JavaScript, ale podczas ich używania musisz przestrzegać dwóch zasad.

  1. Wywołaj hooki na najwyższym poziomie;
  2. Wywołuj hooki tylko z komponentów React.

Uwaga : Te dwie reguły zostały wprowadzone w hookach reakcyjnych, w przeciwieństwie do bycia częścią samego JavaScriptu.

Przyjrzyjmy się tym zasadom bardziej szczegółowo.

Zadzwoń Hooki na najwyższym poziomie

Nie wywołuj hooków wewnątrz pętli, warunków lub funkcji zagnieżdżonych. Zawsze używaj hooków na najwyższym poziomie funkcji React. Przestrzegając tej zasady, zapewniasz, że hooki są wywoływane w tej samej kolejności za każdym razem, gdy renderowany jest komponent. To właśnie pozwala Reactowi na poprawne zachowanie stanu hooków między wielokrotnymi useState i useEffect .

Stwórzmy składnik Form , który będzie miał dwa stany:

  • accountName
  • accountDetail

Te stany będą miały wartości domyślne, użyjemy zaczepu useEffect , aby zachować stan w pamięci lokalnej naszej przeglądarki lub w tytule naszego dokumentu.

Teraz ten składnik może pomyślnie zarządzać swoim stanem, jeśli pozostanie taki sam między wieloma wywołaniami useState i useEffect .

 function Form() { // 1. Use the accountName state variable const [accountName, setAccountName] = useState('David'); // 2. Use an effect for persisting the form useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); // 3. Use the accountDetail state variable const [accountDetail, setAccountDetail] = useState('Active'); // 4. Use an effect for updating the title useEffect(function updateStatus() { document.title = accountName + ' ' + accountDetail; }); // ... }

Jeśli zmieni się kolejność naszych hooków (co może być możliwe, gdy zostaną wywołane w pętlach lub warunkach warunkowych), Reactowi trudno będzie wymyślić, jak zachować stan naszego komponentu.

 // ------------ useState('David') // 1. Initialize the accountName state variable with 'David' useEffect(persistForm) // 2. Add an effect for persisting the form useState('Active') // 3. Initialize the accountdetail state variable with 'Active' useEffect(updateStatus) // 4. Add an effect for updating the status // ------------- // Second render // ------------- useState('David') // 1. Read the accountName state variable (argument is ignored) useEffect(persistForm) // 2. Replace the effect for persisting the form useState('Active') // 3. Read the accountDetail state variable (argument is ignored) useEffect(updateStatus) // 4. Replace the effect for updating the status // ...

To jest kolejność, w jakiej React nazywa nasze hooki. Ponieważ kolejność pozostaje taka sama, będzie w stanie zachować stan naszego komponentu. Ale co się stanie, jeśli umieścimy wywołanie Hook w warunku?

 // We're breaking the first rule by using a Hook in a condition if (accountName !== '') { useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); }

accountName !== '' jest true przy pierwszym renderowaniu, więc uruchamiamy ten hook. Jednak przy następnym renderowaniu użytkownik może wyczyścić formularz, czyniąc warunek false . Teraz, gdy pomijamy ten hook podczas renderowania, kolejność wywołań hooka staje się inna:

 useState('David') // 1. Read the accountName state variable (argument is ignored) // useEffect(persistForm) // This Hook was skipped! useState('Active') // 2 (but was 3). Fail to read the accountDetails state variable useEffect(updateStatus) // 3 (but was 4). Fail to replace the effect

React nie wiedziałby, co zwrócić przy drugim wywołaniu funkcji useState Hook. React spodziewał się, że drugie wywołanie hooka w tym komponencie odpowiada efektowi persistForm , tak jak podczas poprzedniego renderowania — ale już tak nie jest. Od tego momentu każde następne wywołanie Hook po tym, które pominęliśmy, również przesunęłoby się o jeden — prowadząc do błędów.

Dlatego hooki muszą być wywoływane na najwyższym poziomie naszych komponentów. Jeśli chcemy uruchomić efekt warunkowo, możemy umieścić ten warunek w naszym hooku.

Uwaga : zapoznaj się z dokumentacją React Hook, aby przeczytać więcej na ten temat.

Wywołuj hooki tylko z komponentów React

Nie wywołuj hooków ze zwykłych funkcji JavaScript. Zamiast tego możesz wywoływać hooki z komponentów funkcyjnych React. Przyjrzyjmy się różnicy między funkcją JavaScript a komponentem React poniżej:

Funkcja JavaScript

 import { useState } = "react"; function toCelsius(fahrenheit) { const [name, setName] = useState("David"); return (5/9) * (fahrenheit-32); } document.getElementById("demo").innerHTML = toCelsius;

Tutaj importujemy hook useState z pakietu React, a następnie deklarujemy naszą funkcję. Ale jest to niepoprawne, ponieważ nie jest to komponent React.

Funkcja reakcji

 import React, { useState} from "react"; import ReactDOM from "react-dom"; function Account(props) { const [name, setName] = useState("David"); return <p>Hello, {name}! The price is <b>{props.total}</b> and the total amount is <b>{props.amount}</b></p> } ReactDom.render( <Account total={20} amount={5000} />, document.getElementById('root') );

Mimo że korpus obu wygląda podobnie, ten drugi staje się komponentem, gdy importujemy Reacta do pliku. To właśnie umożliwia nam używanie w środku takich rzeczy jak hooki JSX i React.

Jeśli zdarzyło Ci się zaimportować preferowany hook bez importowania Reacta (co czyni go zwykłą funkcją), nie będziesz mógł użyć zaimportowanego hooka, ponieważ hook jest dostępny tylko w komponencie React.

Wywołaj hooki z niestandardowych hooków

Niestandardowy hook to funkcja JavaScript, której nazwa zaczyna się od use i która może wywoływać inne hooki. Na przykład useUserName jest używane poniżej niestandardowego hooka, który wywołuje useState i useEffect . Pobiera dane z API, przechodzi przez dane w pętli i wywołuje setIsPresent() , jeśli określona nazwa użytkownika, którą otrzymał, jest obecna w danych API.

 export default function useUserName(userName) { const [isPresent, setIsPresent] = useState(false); useEffect(() => { const data = MockedApi.fetchData(); data.then((res) => { res.forEach((e) => { if (e.name === userName) { setIsPresent(true); } }); }); }); return isPresent; }

Możemy następnie ponownie wykorzystać funkcjonalność tego haka w innych miejscach, w których potrzebujemy takich w naszej aplikacji. W takich miejscach, poza potrzebami, nie musimy już wywoływać useState lub useEffect .

Przestrzegając tej zasady, zapewniasz, że cała logika stanowa w komponencie jest wyraźnie widoczna w jego kodzie źródłowym.

Wtyczka ESLint

Wtyczka ESLint o nazwie eslint-plugin-react-hooks wymusza powyższe zasady. Przydaje się to w egzekwowaniu zasad podczas pracy nad projektem. Proponuję skorzystać z tej wtyczki podczas pracy nad swoim projektem, zwłaszcza podczas pracy z innymi. Możesz dodać tę wtyczkę do swojego projektu, jeśli chcesz ją wypróbować:

 // Your ESLint configuration { "plugins": [ // ... "react-hooks" ], "rules": { // ... "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies } }

Ta wtyczka jest domyślnie dołączona do aplikacji Create React. Nie musisz więc go dodawać, jeśli uruchamiasz swoje aplikacje React za pomocą aplikacji Create-React-App.

Myślenie w hakach

Przyjrzyjmy się pokrótce komponentom class i komponentom funkcjonalnym (z hookami), zanim przejdziemy do kilku najlepszych praktyk dotyczących hooków.

Najprostszym sposobem zdefiniowania komponentu w React jest napisanie funkcji JavaScript, która zwraca element React:

 function Welcome(props) { return <h1>Hello, {props.name}</h1>; }

Komponent Welcome akceptuje props , czyli obiekt zawierający dane i zwracający element React. Następnie możemy zaimportować i wyrenderować ten komponent w innym komponencie.

Komponent class wykorzystuje metodologię programowania o nazwie Encapsulation , co w zasadzie oznacza, że ​​wszystko, co dotyczy komponentu klasy, będzie w nim mieszkać. Metody cyklu życia ( constructors , componentDidMount() , render , itd.) nadają komponentom przewidywalną strukturę.

Enkapsulacja jest jedną z podstaw programowania obiektowego (ang. O bject-Oriented P rograming ). Odnosi się do grupowania danych w ramach metod operujących na tych danych i służy do ukrywania wartości lub stanu obiektu danych strukturalnych wewnątrz klasy — zapobiegając bezpośredniemu dostępowi do nich nieupoważnionych stron.

W przypadku hooków skład komponentu zmienia się z kombinacji hooków cyklu życia — w funkcje z pewnym renderowaniem na końcu.

Komponent funkcji

Poniższy przykład pokazuje, jak niestandardowe hooki mogą być używane w komponencie funkcjonalnym (bez pokazywania treści). Jednak to, co robi lub może zrobić, nie jest ograniczone. Może to być tworzenie instancji zmiennych stanu, konsumowanie kontekstów, subskrybowanie komponentu z różnymi efektami ubocznymi — lub wszystkie powyższe, jeśli używasz niestandardowego zaczepu!

 function { useHook{...}; useHook{...}; useHook{...}; return (
...
); }

Składnik klasy

Komponent class wymaga rozszerzenia z React.Component i utworzenia funkcji render , która zwraca element React. To wymaga więcej kodu, ale daje też pewne korzyści.

 class { constructor(props) {...} componentDidMount() {...} componentWillUnmount() {...} render() {...} }

Korzystanie z funkcjonalnych komponentów w React daje pewne korzyści:

  1. Łatwiej będzie oddzielić komponenty kontenerowe i prezentacyjne, ponieważ musisz więcej pomyśleć o stanie swojego komponentu, jeśli nie masz dostępu do setState() w swoim komponencie.
  2. Komponenty funkcjonalne są znacznie łatwiejsze do odczytania i przetestowania , ponieważ są zwykłymi funkcjami JavaScript bez stanów lub haczyków cyklu życia.
  3. W efekcie otrzymujesz mniej kodu.
  4. Zespół React wspomniał, że w przyszłych wersjach Reacta może nastąpić wzrost wydajności komponentów funkcjonalnych.

Prowadzi to do pierwszej najlepszej praktyki podczas korzystania z hooków reakcji.

Najlepsze praktyki dotyczące haków

1. Uprość swoje hooki

Prostota React Hooks da Ci możliwość efektywnego kontrolowania i manipulowania tym, co dzieje się w komponencie przez cały okres jego eksploatacji. Unikaj pisania własnych hooków tak często, jak to tylko możliwe ; możesz useState() lub useEffect() zamiast tworzyć własne podpięcie.

Jeśli zauważysz, że korzystasz z wielu niestandardowych hooków, które są powiązane pod względem funkcjonalności, możesz stworzyć niestandardowy hook, który będzie dla nich opakowaniem. Przyjrzyjmy się dwóm różnym elementom funkcjonalnym z haczykami poniżej.

Komponent funkcjonalny v1

 function { useHook(...); useHook(...); useHook(...); return( <div>...</div> ); }

Komponent funkcjonalny v2

 function { useCustomHook(...); useHook(...); useHook(...); return( <div>...</div> ); }

v2 jest lepszą wersją, ponieważ sprawia, że ​​hook jest prosty, a wszystkie inne useHook są odpowiednio wbudowane. Pozwala nam to tworzyć funkcje, które można ponownie wykorzystać w różnych komponentach, a także daje nam więcej możliwości efektywnej kontroli i manipulowania naszymi komponentami. Zamiast stosować v1, w której nasze komponenty są zaśmiecone hookami, powinieneś użyć wersji v2, która ułatwi debugowanie, a twój kod będzie czystszy.

2. Zorganizuj i ustrukturyzuj swoje haczyki

Jedną z zalet React Hooks jest możliwość pisania mniej kodu, który jest łatwy do odczytania. W niektórych przypadkach ilość funkcji useEffect() i useState() może być nadal myląca. Jeśli utrzymasz swój komponent w porządku, pomoże to w czytelności i zapewni spójny i przewidywalny przepływ komponentów. Jeśli twoje niestandardowe hooki są zbyt skomplikowane, zawsze możesz podzielić je na podrzędne hooki. Wyodrębnij logikę swojego komponentu do niestandardowych hooków, aby twój kod był czytelny.

3. Użyj fragmentów kodu React Hooks

Fragmenty haków reakcji to rozszerzenie Visual Studio Code, które ułatwia i przyspiesza hakowanie reakcji. Obecnie obsługiwanych jest pięć hooków:

  • useState()
  • useEffect()
  • useContext()
  • useCallback()
  • useMemo()

Dodano również inne fragmenty. Próbowałem pracować z tymi hookami i była to jedna z najlepszych praktyk, których osobiście używałem podczas pracy z nimi.

Istnieją dwa sposoby dodawania fragmentów kodu React Hooks do projektu:

  1. Komenda
    Uruchom VS Code Quick open ( Ctrl + P ), wklej ext install ALDuncanson.react-hooks-snippets i naciśnij Enter .
  2. Rynek rozszerzeń
    Uruchom „VS Code Extension Marketplace” ( Ctrl + Shift + X ) i wyszukaj „React Hook Snippets”. Następnie poszukaj ikony „Alduncanson”.

Polecam pierwszy fragment. Przeczytaj więcej o fragmentach tutaj lub sprawdź najnowsze fragmenty hooków tutaj.

4. Uwzględnij zasady hooków

Staraj się zawsze uwzględniać dwie zasady hooków, których nauczyliśmy się wcześniej, podczas pracy z hookami reakcyjnymi.

  • Wywołuj swoje hooki tylko na najwyższym poziomie. Nie wywołuj hooków wewnątrz pętli, warunków lub funkcji zagnieżdżonych.
  • Zawsze wywołuj hooki z komponentów funkcji React lub z własnych hooków, nie wywołuj hooków ze zwykłych funkcji JavaScript.

Wtyczka ESlint o nazwie eslint-plugin-react-hooks wymusza te dwie zasady, możesz dodać tę wtyczkę do swojego projektu, jeśli chcesz, jak wyjaśniliśmy powyżej w sekcji reguł hooków.

Najlepsze praktyki nie zostały w pełni rozwiązane, ponieważ hooki są wciąż stosunkowo nowe. Tak więc adopcja powinna być podjęta z ostrożnością, którą można by podjąć przy adopcji w każdej wczesnej technologii. Mając to na uwadze, hooki są drogą do przyszłości Reacta.

Wniosek

Mam nadzieję, że podobał Ci się ten samouczek. Poznaliśmy dwie najważniejsze zasady hooków reakcyjnych i jak efektywnie myśleć w hookach. Przyjrzeliśmy się komponentom funkcjonalnym i niektórym najlepszym praktykom w pisaniu hooków we właściwy i skuteczny sposób. Choć zasady są krótkie, ważne jest, aby były one Twoim kompasem przewodnim podczas pisania zasad. Jeśli masz skłonność do zapomnienia, możesz skorzystać z wtyczki ESLint, aby to wymusić.

Mam nadzieję, że wyciągniesz wszystkie wnioski z lekcji w swoim następnym projekcie React. Powodzenia!

Zasoby

  • „Przedstawiamy hooki”, React Docs
  • „Funkcjonalne a komponenty klasowe w reakcji”, David Joch, Medium
  • „Miksyny uważane za szkodliwe”, Dan Abramov, blog React
  • „React Hooks: najlepsze praktyki i zmiana sposobu myślenia”, Bryan Manuele, Medium
  • „React Hooks Snippets For VS Code”, Anthony Davis, Visual Code Marketplace