Hooki to funkcje wielokrotnego użytku. Pozwalają ci używać były i inne funkcje (np. metody cyklu życia itd.) bez pisania klasy. Funkcje przechwytujące pozwalają nam „zahaczyć się” w Cykl życia stanu reakcji używanie komponentów funkcjonalnych, co pozwala nam manipulować stanem naszych komponentów funkcjonalnych bez konieczności konwertowania ich na komponenty klas.
React wprowadzone haki w wersji 16.8 i od tego czasu dodaje więcej. Niektóre są bardziej używane i popularne niż inne, na przykład useEffect
, useState
, useContext
haki. Nie mam wątpliwości, że sięgałeś po nie, jeśli pracujesz z Reactem.
Ale mnie interesują mniej znane haki React. Chociaż wszystkie haczyki Reacta są interesujące na swój sposób, jest ich pięć, które naprawdę chcę wam pokazać, ponieważ mogą nie pojawiać się w codziennej pracy — a może tak, a znajomość ich daje dodatkowe supermoce.
Spis treści
useReducer
Połączenia useReducer
hook to narzędzie do zarządzania stanem, podobnie jak inne hooki. W szczególności jest to alternatywa dla useState
hak.
Jeśli używasz useReducer
zaczep, aby zmienić dwa lub więcej stanów (lub akcji), nie będziesz musiał manipulować tymi stanami indywidualnie. Hak śledzi wszystkie stany i wspólnie nimi zarządza. Innymi słowy: zarządza i ponownie renderuje zmiany stanu. w przeciwieństwie do useState
hak, useReducer
jest łatwiejsze, jeśli chodzi o obsługę wielu stanów w złożonych projektach.
Przypadków użycia
useReducer
może pomóc w zmniejszeniu złożoności pracy z wieloma stanami. Użyj go, gdy okaże się, że musisz zbiorczo śledzić wiele stanów, ponieważ pozwala traktować zarządzanie stanami i logikę renderowania komponentu jako oddzielne kwestie.
Składnia
useReducer
akceptuje trzy argumenty, z których jeden jest opcjonalny:
- funkcja reduktora
initialState
- an
init
funkcja (opcjonalnie)
const [state, dispatch] = useReducer(reducer, initialState)
const [state, dispatch] = useReducer(reducer, initialState initFunction) // in the case where you initialize with the optional 3rd argument
Przykład
Poniższy przykład to interfejs zawierający dane wejściowe, licznik i przycisk. Interakcja z każdym elementem aktualizuje stan. Zauważ jak useReducer
pozwala nam zdefiniować wiele spraw jednocześnie, zamiast konfigurować je indywidualnie.
import { useReducer } from 'react';
const reducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
case 'USER_INPUT':
return { ...state, userInput: action.payload };
case 'TOGGLE_COLOR':
return { ...state, color: !state.color };
default:
throw new Error();
}
}
function App() {
const [state, dispatch] = useReducer(reducer, { count: 0, userInput: '', color: false })
return (
<main className="App, App-header" style={{ color: state.color ? '#000' : '#FF07FF'}}>
<input style={{margin: '2rem'}}
type="text"
value={state.userInput}
onChange={(e) => dispatch({ type: 'USER_INPUT', payload: e.target.value })}
/>
<br /><br />
<p style={{margin: '2rem'}} >{state.count}</p>
<section style={{margin: '2rem'}}>
<button onClick={(() => dispatch({ type: 'DECREMENT' }))}>-</button>
<button onClick={(() => dispatch({ type: 'INCREMENT' }))}>+</button>
<button onClick={(() => dispatch({ type: 'TOGGLE_COLOR' }))}>Color</button>
</section>
<br /><br />
<p style={{margin: '2rem'}}>{state.userInput}</p>
</main>
);
}
export default App;
Z powyższego kodu zauważyłem, jak jesteśmy w stanie łatwo zarządzać kilkoma stanami w reduktor (przypadek przełącznika), to pokazuje korzyści z useReducer
. Jest to moc, jaką daje podczas pracy w złożonych aplikacjach z wieloma stanami.
useRef
Połączenia useRef
hook służy do tworzenia referencji na elementach w celu uzyskania dostępu do DOM. Ale co więcej, zwraca obiekt z .current
właściwość, która może być używana przez cały cykl życia składnika, umożliwiając zachowanie danych bez powodowania ponownego renderowania. Więc useRef
wartość pozostaje taka sama między renderowaniami; aktualizacja odniesienia nie powoduje ponownego renderowania.
Przypadków użycia
Sięgnij po useRef
zaczepić, gdy chcesz:
- Manipuluj DOM za pomocą przechowywanych informacji mutowalnych.
- Dostęp do informacji z komponentów podrzędnych (elementów zagnieżdżonych).
- Ustaw ostrość na elemencie.
Jest to najbardziej przydatne podczas przechowywania zmiennych danych w aplikacji bez powodowania ponownego renderowania.
Składnia
useRef
akceptuje tylko jeden argument, którym jest wartość początkowa.
const newRefComponent = useRef(initialValue);
Przykład
Tutaj użyłem useRef
i useState
hook, aby pokazać, ile razy aplikacja renderuje zaktualizowany stan podczas wpisywania tekstu.
import './App.css'
function App() {
const [anyInput, setAnyInput] = useState(" ");
const showRender = useRef(0);
const randomInput = useRef();
const toggleChange = (e) => {
setAnyInput (e.target.value);
showRender.current++;
}
const focusRandomInput = () => {
randomInput.current.focus();
}
return (
<div className="App">
<input className="TextBox"
ref ={randomInput} type="text" value={anyInput} onChange={toggleChange}
/>
<h3>Amount Of Renders: {showRender.current}</h3>
<button onClick={focusRandomInput}>Click To Focus On Input </button>
</div>
);
}
export default App;
Zwróć uwagę, jak wpisanie każdego znaku w polu tekstowym aktualizuje stan aplikacji, ale nigdy nie powoduje pełnego ponownego renderowania.
useImperativeHandle
Wiesz, w jaki sposób komponent potomny ma dostęp do funkcji wywoływania przekazywanych im z komponentu nadrzędnego? Rodzice przekazują je za pomocą rekwizytów, ale to przekazywanie jest „jednokierunkowe” w tym sensie, że rodzic nie jest w stanie wywołać funkcji, która jest w dziecku.
Cóż, useImperativeHandle
umożliwia rodzicowi dostęp do funkcji komponentu potomnego.
Jak to działa?
- Funkcja jest zdefiniowana w komponencie potomnym.
- A
ref
jest dodawany w rodzicu. - Używamy pliki
forwardRef
, zezwalając naref
który został określony jako przekazany dziecku. useImperativeHandle
eksponuje funkcje dziecka poprzezref
.
Przypadków użycia
useImperativeHandle
działa dobrze, gdy chcesz, aby zmiany w składniku nadrzędnym miały wpływ na komponent nadrzędny. Tak więc takie rzeczy jak zmiana ostrości, zwiększanie i zmniejszanie oraz rozmyte elementy mogą być sytuacjami, w których sięgasz po ten hak, aby rodzic mógł zostać odpowiednio zaktualizowany.
Składnia
useImperativeHandle (ref, createHandle, [dependencies])
Przykład
W tym przykładzie mamy dwa przyciski, jeden w komponencie nadrzędnym, a drugi w potomnym. Kliknięcie przycisku rodzica pobiera dane od dziecka, co pozwala nam manipulować komponentem rodzica. Jest skonfigurowany tak, że kliknięcie przycisku dziecka nie przekazuje niczego z komponentu rodzica do dziecka, aby pomóc zilustrować, w jaki sposób przekazujemy rzeczy w przeciwnym kierunku.
// Parent component
import React, { useRef } from "react";
import ChildComponent from "./childComponent";
import './App.css';
function useImperativeHandle() {
const controlRef = useRef(null);
return (
onClick={
() => {
controlRef.current.controlPrint();
}
}
>
Parent Box
);
}
export default useImperativeHandle;
// Child component
import React, { forwardRef, useImperativeHandle, useState } from "react";
const ChildComponent = forwardRef((props, ref) => {
const [print, setPrint] = useState(false);
useImperativeHandle(ref, () => ({
controlPrint()
{ setPrint(!print); },
})
);
return (
<>
Child Box
{ print && I am from the child component }
);
});
export default ChildComponent;
Wydajność
useMemo
useMemo
to jeden z najmniej używanych, ale najciekawszych hooków Reacta. Może poprawić wydajność i zmniejszyć opóźnienia, szczególnie w przypadku dużych obliczeń w Twojej aplikacji. Jak to? Za każdym razem, gdy stan komponentu aktualizuje się i komponenty są ponownie renderowane, useMemo
hook zapobiega konieczności ponownego obliczania przez Reacta wartości.
Widzisz, funkcje reagują na zmiany stanu. The useMemo
hak przejmuje funkcję i zwraca wartość zwracaną tej funkcji. Buforuje tę wartość, aby zapobiec dodatkowym nakładom pracy na ponowne jej renderowanie, a następnie zwraca ją, gdy zmieni się jedna z zależności.
Ten proces jest wywoływany zapamiętywanie i to pomaga zwiększyć wydajność, pamiętając wartość z poprzedniego żądania, aby można było jej użyć ponownie bez powtarzania całej tej matematyki.
Przypadków użycia
Najlepszymi przypadkami użycia będą za każdym razem, gdy pracujesz z ciężkimi obliczeniami, w których chcesz przechowywać wartość i używać jej przy kolejnych zmianach stanu. Może to być niezła poprawa wydajności, ale zbyt częste jej używanie może mieć dokładnie odwrotny skutek, ponieważ zabiera pamięć aplikacji.
Składnia
useMemo( () =>
{ // Code goes here },
[]
)
Przykład
Po kliknięciu przycisku ten miniprogram wskazuje, kiedy liczba jest parzysta lub nieparzysta, a następnie podnosi wartość do kwadratu. Dodałem wiele zer do pętli, aby zwiększyć jej moc obliczeniową. Zwraca wartość w rozlanych sekundach i nadal działa dobrze ze względu na useMemo
hak.
// UseMemo.js
import React, { useState, useMemo } from 'react'
function Memo() {
const [memoOne, setMemoOne] = useState(0);
const incrementMemoOne = () => { setMemoOne(memoOne + 1) }
const isEven = useMemo(() => {
let i = 0 while (i < 2000000000) i++ return memoOne % 2 === 0
},
[memoOne]);
const square = useMemo(()=> {
console.log("squared the number"); for(var i=0; i < 200000000; i++);
return memoOne * memoOne;
},
[memoOne]);
return (
Memo One -
{ memoOne }
{ isEven ? 'Even' : 'Odd' } { square }
);
}
export default Memo
Wydajność
useMemo
jest trochę jak ten useCallback
hak, ale różnica polega na tym useMemo
może przechowywać zapamiętaną wartość z funkcji, gdzie useCallback
przechowuje samą zapamiętaną funkcję.
useCallback
Połączenia useCallback
hak jest kolejnym interesującym, a ostatnia sekcja była rodzajem ostrzeżenia spoilera na temat tego, co robi.
Jak właśnie widzieliśmy, useCallback
działa jak useMemo
zahaczają o to, że oboje używają zapamiętywania do buforowania czegoś do późniejszego użycia. Podczas gdy useMemo
przechowuje obliczenia funkcji jako wartość w pamięci podręcznej, useCallback
przechowuje i zwraca funkcję.
Przypadków użycia
Jak useMemo, useCallback
jest fajną optymalizacją wydajności, ponieważ przechowuje i zwraca zapamiętane wywołanie zwrotne i wszelkie jego zależności bez ponownego renderowania.
Składnia
const getMemoizedCallback = useCallback (
() => { doSomething () }, []
);
Przykład
{ useCallback, useState } from "react";
import CallbackChild from "./UseCallback-Child";
import "./App.css"
export default function App() {
const [toggle, setToggle] = useState(false);
const [data, setData] = useState("I am a data that would not change at every render, thanks to the useCallback");
const returnFunction = useCallback(
(name) =>
{ return data + name; }, [data]
);
return (
onClick={() => {
setToggle(!toggle);
}}
>
{" "}
// Click To Toggle
{ toggle && h1. Toggling me no longer affects any function }
);
}
// The Child component
import React, { useEffect } from "react";
function CallbackChild(
{ returnFunction }
) {
useEffect(() =>
{ console.log("FUNCTION WAS CALLED"); },
[returnFunction]);
return { returnFunction(" Hook!") };
}
export default CallbackChild;
Wydajność
Końcowe przemyślenia
No to jedziemy! Właśnie spojrzeliśmy na pięć super poręcznych haczyków React, które moim zdaniem często są pomijane. Podobnie jak w przypadku wielu takich łapanek, po prostu drapiemy powierzchnię tych haków. Każdy z nich ma swoje własne niuanse i względy, które należy wziąć pod uwagę podczas ich używania. Ale miejmy nadzieję, że masz dobre ogólne pojęcie o tym, czym one są i kiedy mogą być lepiej dopasowane niż inny haczyk, po który możesz sięgać częściej.
Najlepszym sposobem na ich pełne zrozumienie jest praktyka. Zachęcam więc do przećwiczenia używania tych haczyków w swojej aplikacji, aby lepiej zrozumieć. W tym celu możesz uzyskać bardziej szczegółowe informacje, sprawdzając następujące zasoby: