I ganci sono funzioni riutilizzabili. Ti permettono di usare stato e altre funzionalità (ad esempio metodi del ciclo di vita e così via) senza scrivere una classe. Le funzioni di hook ci consentono di "agganciare" il Reagire al ciclo di vita dello stato utilizzando componenti funzionali, consentendoci di manipolare lo stato dei nostri componenti funzionali senza doverli convertire in componenti di classe.
Reagire ganci introdotti nella versione 16.8 e da allora ne ha aggiunti altri. Alcuni sono più usati e popolari di altri, come useEffect
, useState
e useContext
ganci. Non ho dubbi sul fatto che tu abbia raggiunto quelli se lavori con React.
Ma quello che mi interessa sono gli hook React meno conosciuti. Sebbene tutti gli hook di React siano interessanti a modo loro, ce ne sono cinque che voglio davvero mostrarti perché potrebbero non apparire nel tuo lavoro quotidiano – o forse lo fanno e conoscerli ti dà alcuni superpoteri in più.
Sommario
useReducer
Il useReducer
hook è uno strumento di gestione dello stato come altri hook. Nello specifico, è un'alternativa al useState
gancio.
Se si utilizza il useReducer
hook per cambiare due o più stati (o azioni), non dovrai manipolare quegli stati individualmente. Il gancio tiene traccia di tutti gli stati e li gestisce collettivamente. In altre parole: gestisce e ripropone i cambiamenti di stato. non mi piace il useState
gancio, useReducer
è più facile quando si tratta di gestire molti stati in progetti complessi.
Utilizzo Tipico
useReducer
può aiutare a ridurre la complessità del lavoro con più stati. Usalo quando ti trovi a dover tenere traccia di più stati collettivamente, poiché ti consente di trattare la gestione degli stati e la logica di rendering di un componente come preoccupazioni separate.
Sintassi
useReducer
accetta tre argomenti, uno dei quali è facoltativo:
- una funzione di riduzione
initialState
- an
init
funzione (opzionale)
const [state, dispatch] = useReducer(reducer, initialState)
const [state, dispatch] = useReducer(reducer, initialState initFunction) // in the case where you initialize with the optional 3rd argument
Esempio
L'esempio seguente è un'interfaccia che contiene un input di testo, un contatore e un pulsante. L'interazione con ogni elemento aggiorna lo stato. Nota come useReducer
ci consente di definire più casi contemporaneamente anziché configurarli singolarmente.
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;
Dal codice sopra, ho notato come siamo in grado di gestire facilmente diversi stati nel file riduttore (switch-case), questo mostra il vantaggio del useReducer
. Questa è la potenza che offre quando si lavora in applicazioni complesse con più stati.
useRef
Il useRef
hook viene utilizzato per creare riferimenti sugli elementi per accedere al DOM. Ma più di questo, restituisce un oggetto con a .current
proprietà che può essere utilizzata durante l'intero ciclo di vita di un componente, consentendo ai dati di persistere senza causare un nuovo rendering. Così la useRef
il valore rimane lo stesso tra i rendering; l'aggiornamento del riferimento non attiva un nuovo rendering.
Utilizzo Tipico
Raggiungi il useRef
aggancia quando vuoi:
- Manipolare il DOM con informazioni mutevoli memorizzate.
- Accedere alle informazioni dai componenti figlio (elementi nidificati).
- Metti a fuoco un elemento.
È molto utile quando si archiviano dati mutabili nell'app senza causare un nuovo rendering.
Sintassi
useRef
accetta solo un argomento, che è il valore iniziale.
const newRefComponent = useRef(initialValue);
Esempio
Qui ho usato il useRef
ed useState
hook per mostrare la quantità di volte in cui un'applicazione esegue il rendering di uno stato aggiornato durante la digitazione di un input di testo.
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;
Nota come la digitazione di ogni carattere nel campo di testo aggiorna lo stato dell'app, ma non attiva mai un rendering completo.
useImperativeHandle
Sai come un componente figlio ha accesso alle funzioni di chiamata passate a loro dal componente padre? I genitori li trasmettono tramite oggetti di scena, ma quel trasferimento è "unidirezionale", nel senso che il genitore non è in grado di chiamare una funzione che è nel bambino.
Bene, useImperativeHandle
consente a un genitore di accedere alle funzioni di un componente figlio.
Come funziona?
- Una funzione è definita nel componente figlio.
- A
ref
viene aggiunto nel genitore. - Usiamo
forwardRef
, permettendo ilref
che è stato definito per essere trasmesso al bambino. useImperativeHandle
espone le funzioni del bambino tramite ilref
.
Utilizzo Tipico
useImperativeHandle
funziona bene quando si desidera che un componente padre sia influenzato dalle modifiche nel figlio. Quindi, cose come una messa a fuoco modificata, l'incremento e il decremento e gli elementi sfocati possono essere situazioni in cui ti ritrovi a raggiungere questo gancio in modo che il genitore possa essere aggiornato di conseguenza.
Sintassi
useImperativeHandle (ref, createHandle, [dependencies])
Esempio
In questo esempio, abbiamo due pulsanti, uno in un componente padre e uno in un figlio. Facendo clic sul pulsante genitore si recuperano i dati dal figlio, consentendoci di manipolare il componente genitore. È impostato in modo che facendo clic sul pulsante figlio non passi nulla dal componente genitore al figlio per aiutare a illustrare come stiamo passando le cose nella direzione opposta.
// 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;
Uscita
useMemo
useMemo
è uno degli hook React meno utilizzati ma più interessanti. Può migliorare le prestazioni e ridurre la latenza, in particolare su calcoli di grandi dimensioni nella tua app. Come mai? Ogni volta che lo stato di un componente si aggiorna e si esegue nuovamente il rendering, il file useMemo
hook impedisce a React di dover ricalcolare i valori.
Vedete, le funzioni rispondono ai cambiamenti di stato. Il useMemo
hook prende una funzione e restituisce il valore di ritorno di quella funzione. Memorizza quel valore nella cache per evitare di spendere ulteriori sforzi per rieseguire il rendering, quindi lo restituisce quando una delle dipendenze è cambiata.
Questo processo è chiamato memoizzazione ed è ciò che aiuta a migliorare le prestazioni ricordando il valore di una richiesta precedente in modo che possa essere riutilizzato senza ripetere tutta quella matematica.
Utilizzo Tipico
I migliori casi d'uso si verificheranno ogni volta che si lavora con calcoli pesanti in cui si desidera archiviare il valore e utilizzarlo nei successivi cambiamenti di stato. Può essere una bella vittoria in termini di prestazioni, ma usarla troppo può avere l'effetto esattamente opposto occupando la memoria della tua app.
Sintassi
useMemo( () =>
{ // Code goes here },
[]
)
Esempio
Quando si fa clic sul pulsante, questo mini-programma indica quando un numero è pari o dispari, quindi quadra il valore. Ho aggiunto molti zeri al ciclo per aumentarne la potenza di calcolo. Restituisce il valore in secondi versati e funziona ancora bene grazie a useMemo
gancio.
// 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
Uscita
useMemo
è un po' come il useCallback
gancio, ma la differenza è che useMemo
può memorizzare un valore memorizzato da una funzione, dove useCallback
memorizza la funzione memorizzata stessa.
useCallback
Il useCallback
hook è un altro interessante e l'ultima sezione era una sorta di avviso spoiler per quello che fa.
Come abbiamo appena visto, useCallback
funziona come useMemo
hook in che entrambi usano la memorizzazione nella cache di qualcosa per un uso successivo. Mentre useMemo
memorizza il calcolo di una funzione come valore memorizzato nella cache, useCallback
memorizza e restituisce una funzione.
Utilizzo Tipico
Come useMemo, useCallback
è una buona ottimizzazione delle prestazioni in quanto memorizza e restituisce un callback memorizzato e tutte le sue dipendenze senza un nuovo rendering.
Sintassi
const getMemoizedCallback = useCallback (
() => { doSomething () }, []
);
Esempio
{ 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;
Uscita
Conclusioni
Eccoci! Abbiamo appena esaminato cinque ganci React super pratici che penso vengano spesso trascurati. Come con molti rastrellamenti come questo, stiamo semplicemente grattando la superficie di questi ganci. Ognuno di loro ha le proprie sfumature e considerazioni di cui tenere conto quando li usi. Ma si spera che tu abbia una bella idea di alto livello di cosa sono e quando potrebbero adattarsi meglio di un altro gancio che potresti raggiungere più spesso.
Il modo migliore per comprenderli appieno è la pratica. Quindi ti incoraggio a esercitarti nell'uso di questi hook nella tua applicazione per una migliore comprensione. Per questo, puoi approfondire molto controllando le seguenti risorse: