Le cose più importanti da ricordare sui ganci:

importare { useState,useEffect } da "react";

esportare la funzione predefinita FunctionComponent() {
const [value, setValue] = useState(1);
const [doubleValue, setDoubleValue] = useState(1);
se (valore > 3) {
  useEffect(() => setDoubleValue(valore * 2),[value]);
}

return (
  <>
    <p>{Singolo ${valore} Doppio ${doppioValore}`}</p>
    <button onclick="{()" > setValue(valore + 1)}&gt;Controllo</button>
  </>
);
}
```

All'inizio, si riceverà un avviso da eslint:

<code>srcFunctionComponent.js
   Riga 11:5: React Il gancio "useEffect" è chiamato in modo condizionato. <strong>React Ganci</strong> deve essere chiamato esattamente nello stesso ordine in ogni componente render .eslintreact-hooks/rules-of-hooks

Come si può vedere, si tratta solo di un avviso di eslint, quindi è possibile disabilitarlo aggiungendo un comando dal basso all'inizio del file FunzioneComponente

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

e funzionerà, ma solo finché non verrà soddisfatta la condizione che fa funzionare il nostro Hook. La cosa successiva che vedremo è questo errore.

Errore non corretto: Renderizzati più ganci rispetto al rendering precedente.
     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

Perché questo accade? L'React si basa sull'ordine in cui vengono chiamati gli hook, in quanto l'React non saprebbe cosa restituire per l'useEffect perché non c'è un hook nella riga da controllare.

Ricordate che eslint è uno strumento potente, che ci aiuta a individuare molti potenziali bug ed errori. Disattivare i suoi avvisi è una cosa pericolosa, controllate sempre se ignorare l'avviso può causare un crash dell'applicazione.

Stato d'uso

Probabilmente sapete come si presenta 😉

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

Quindi, ci sono 4 elementi: stato (valore reattivo), funzione di aggiornamento (setter), aggancio effettivo (funzione) e valore iniziale opzionale. Perché restituisce un array? Perché possiamo ristrutturarlo come vogliamo.

Ora voglio concentrarmi sull'ultimo elemento: il valore iniziale. Esistono due modi per passare lo stato iniziale:

  1. Con un valore predefinito o altro, che verrà richiamato a ogni rendering.
const [value, setValue] = useState(0);
  1. Da una versione di funzione. È molto utile se si vuole eseguire lo stato iniziale solo una volta, al primo rendering. Forse è necessario eseguire molti calcoli complessi per ricevere lo stato iniziale? In questo modo si riduce il costo delle risorse, evviva!
const [value, setValue] = useState(() => {
   console.log("INIT");
   return 0;
 });

Come verificare che il primo modo sia davvero chiamato ad ogni rendering? Creare una funzione e passarla come stato iniziale:

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

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

E ora passate al secondo modo:

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

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

Bello, vero?

rumore.png

Un'altra cosa che può creare bug nel flusso dell'app: probabilmente sapete come aggiornare uno stato, giusto?

setValue(1);

Giusto... ma se volessi aggiornare lo stato in base a uno stato precedente?

setValue(valore + 1);

Sì... Ma no... E se si cerca di chiamare la funzione setter due volte, una dopo l'altra? Il modo consigliato per aggiornare uno stato in base allo stato precedente è utilizzare una funzione. Garantisce che si stia facendo riferimento allo stato precedente

setValue((prevState) => prevState + 1);
// con gli oggetti:
setUser((prevState) => ({ ...prevState, lastName: "Brzeczyszczykiewicz" }));

usaEffetto

Questo hook accetta due argomenti (il secondo è opzionale) e lo usiamo per gestire gli effetti collaterali. A seconda di ciò che passiamo come secondo argomento, l'hook sarà chiamato in modo diverso:

  1. senza secondo argomento - ogni rendering
useEffect(() => {
   doSomething();
 });
  1. array vuoto - solo al primo rendering
useEffect(() => {
   doSomething();
 }, []);
  1. con le dipendenze - ogni volta che il valore nell'array delle dipendenze cambia
useEffect(() => {
   doSomething(valore);
 }, [valore]);

Pulizia

Con useEffect, possiamo usare qualcosa che viene chiamato cleanup. A cosa serve? È molto utile, ma credo sia meglio per pulire gli ascoltatori di eventi. Supponiamo di voler creare un ascoltatore di eventi che dipende da alcuni stati. Non si vuole aggiungere un nuovo ascoltatore di eventi a ogni cambio di stato, perché dopo qualche rendering ci saranno così tanti ascoltatori da influire sulle prestazioni dell'applicazione. Un ottimo modo per evitare queste cose è usare la funzione di pulizia. Come fare? Basta aggiungere una funzione di ritorno a useEffect.

useEffect(() => {
console.log("effetto collaterale 1", count);
return () => {
console.log("DISTRUTTO 1");
};
});

useEffect(() => {
console.log("effetto collaterale 2", count);
return () => {
console.log("DISTRUTTO 2");
};
}, []);

useEffect(() => {
console.log("effetto collaterale 3", count);
return () => {
console.log("DISTRUTTO 3");
};
}, [count]);
```

Poiché si trova all'interno dell'hook useEffect, il ritorno viene chiamato a seconda dell'array di dipendenze: a ogni rendering, solo al primo rendering o quando il valore nell'array di dipendenze cambia. Ma quando il componente viene smontato, la pulizia sarà chiamata sul secondo parametro, indipendentemente da ciò. Il ritorno codice viene richiamato prima del codice effettivo di Hook. È molto logico: prima si pulisce quello vecchio, poi se ne crea uno nuovo. Giusto?

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

Quindi, per prima cosa, riceverete un rimuovere messaggio, allora Aggiungi.

C'è una cosa da tenere presente quando si usa useEffect e il codice asincrono al suo interno. Date un'occhiata al codice qui sotto:

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

All'inizio sembra tutto a posto. Si recuperano alcuni dati e, quando questi arrivano, si aggiorna lo stato. Ed ecco la trappola:

A volte si riceve un avviso di questo tipo:
Impossibile eseguire un aggiornamento di stato React su un componente non montato. Si tratta di un'operazione non necessaria, ma indica una perdita di memoria nell'applicazione. Per risolvere, annullare tutte le sottoscrizioni e le attività asincrone in una funzione di pulizia useEffect.

Il motivo è che il componente può essere smontato nel frattempo, ma l'applicazione cercherà comunque di aggiornare lo stato del componente dopo che la promessa è stata mantenuta. Come comportarsi? È necessario verificare se il componente esiste.

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

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

Nota: esiste un hook molto simile => useLayoutEffect() - il callback viene eseguito dopo il rendering del componente, ma prima che la dom venga aggiornata visivamente. È utile quando si lavora con getBoundingClientRect(), ma si dovrebbe usare useEffect per impostazione predefinita. Perché? Perché può bloccare gli aggiornamenti visivi, quando si ha un codice complesso all'interno dell'effetto Hook.

usaContext

A cosa serve? Condividere dati senza passare oggetti di scena. Consiste nei seguenti elementi:

  1. Contesto creato - dati
  2. Fornitore di contesto - fornire un contesto a tutti i bambini
  3. Valore passato - dati che si desidera condividere
  4. Gancio - per leggere i dati condivisi
const utente = {
nome: "Adam",
cognome: "Kowalski",
};

export const UserContext = createContext(user);

;
```

In child, è necessario importare il contesto e chiamare l'hook useContext, passando il contesto come argomento.

importare { UserContext } da "./App";

const { name } = useContext(UserContext);

restituire <h1>Ciao {nome}<>
```

Voilà. Sembra bello. Soprattutto per passare dati globali come temi, ecc. Non è raccomandato per l'uso in attività con modifiche molto dinamiche.

Naturalmente, possiamo creare un fornitore di contesto personalizzato e un hook personalizzato per ridurre il boilerplate... ma tratterò gli hook personalizzati nel prossimo articolo.

usaRiduttore

Ci consente di gestire lo stato e di renderizzare nuovamente quando lo stato cambia, come useState. È simile al redux reducer. È meglio di useState quando la logica dello stato è più complicata.

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

Esiste anche un terzo argomento che può essere passato a useReducer: la funzione init.

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

A cosa serve? Può essere utilizzato quando si vuole riportare lo stato al suo valore iniziale. Di seguito è riportato un simpatico esempio:

// Genitore
// Bambino
function init(initialNumber) {
return { numero: initialNumber };
}

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

Esportare la funzione predefinita ChildComponent({ getFactorial }) {
const [state, dispatch] = useReducer(reducer, initialNumber, init);

return (
<>
   <h2>Numero: {state.number}</h2>
      <button
        onclick="{()" > dispatch({tipo: "reset", payload: initialNumber })}
      &gt;
        Azzeramento
      </button>
      <button onclick="{()" > dispatch({tipo: "change" })}&gt;Disegna</button>
    </>
  );
}

Numero: {state.number}

ReducerInit.png

useCallback

Quando usarlo? Quando si vuole ottenere l'uguaglianza referenziale (riducendo così il numero di funzioni create). Questo hook restituisce la funzione, a differenza di useMemo che restituisce il valore.

Esempio: Creare una funzione nel componente padre e poi passarla tramite gli oggetti di scena

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

Quindi verificare nel componente figlio quante volte verrà richiamato l'effetto Hook dopo aver aggiunto la funzione all'array delle dipendenze:

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

Verrà registrato nella console a ogni rendering! Anche se i valori all'interno del campo getSquaredValue() non è stata modificata. Ma possiamo evitarlo avvolgendo la funzione in useCallback

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

Possiamo anche passare alcuni parametri a questa funzione:

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

usaMemo

const memoizedValue = useMemo(() => {
   return doSomething(valore);
 }, [valore]);

Dovreste usarlo solo in due scenari:

  1. Se si vuole evitare di richiamare un codice complesso a ogni rendering;
  2. Se si vuole ottenere l'uguaglianza referenziale.

Vediamo un po' più da vicino il secondo caso. Vogliamo usare useEffect con un oggetto come dipendenza. Poiché gli oggetti sono confrontati in base al loro riferimento, useEffect sarà richiamato a ogni rendering. Per evitare questo, possiamo combinare useEffect con useMemo per memorizzare tali oggetti e poi passare gli oggetti memorizzati all'array delle dipendenze. Breve esempio:

Per prima cosa provate a farlo senza useMemo:

const hobbit = { nome: "Bilbo" };

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

Inoltre, riceverete un avviso:

L'oggetto 'hobbit' fa cambiare le dipendenze del gancio useEffect (riga 49) a ogni rendering. Spostarlo all'interno del callback useEffect. In alternativa, avvolgere l'inizializzazione di 'hobbit' nel proprio hook useMemo ().eslintreact-hooks/exhaustive-deps

Poi provate con useMemo:

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

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

usaRef

La cosa più importante è che useRef non attiva il re-rendering (come useState) perché non è collegato al ciclo di rendering: mantiene lo stesso riferimento tra i rendering.

const ref = useRef(0);

Per richiamare il valore salvato, è necessario utilizzare una proprietà current (ref è un oggetto) - corrente

Il secondo caso in cui possiamo usare questo hook è per fare riferimento a elementi all'interno dell'HTML. Ogni elemento ha un attributo ref. Quindi, possiamo gestire il focus, gli eventi e così via.

Il terzo caso è quello in cui possiamo usare i refs per gestire componenti non controllati. Si può leggere di più su di essi in documenti di react,
ma, in breve, si presenta così:

esportare la funzione predefinita UncontrolledForm() {
  const input = useRef();

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

  return (
    
      
      
    
  );
}

Come si può vedere, non c'è un gestore di eventi, ma solo la memorizzazione del valore digitato. È ottimo per gestire i moduli di base, quando si vuole solo leggere i valori salvati quando se ne ha bisogno (come al momento dell'invio).

Bonus: è ottimo quando si ha bisogno di ricordare i valori di uno stato precedente. Si può usare il gancio useEffect, basta passare lo stato al ref.

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

let prevValue = useRef("");

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

 setValue(e.target.value)}>;

Come si può vedere, i ganci non sono così ovvi. Possiamo combinarli per risolvere molti problemi. Sicuramente trarrete grandi benefici dallo studio di questo argomento.

E ci sono anche ganci personalizzati...

In conclusione, Ganci React hanno rivoluzionato il modo in cui Sviluppatori React approccio all'edificio applicazioni web . Fornendo un modo più intuitivo ed efficiente per gestire lo stato e il ciclo di vita dei componenti funzionali, i ganci sono diventati parte integrante del sistema di gestione delle risorse. Sviluppo React .

Sia che siate sviluppatori esperti o che abbiate appena iniziato a usare l'React, la comprensione dei ganci più popolari e dei loro casi d'uso è fondamentale. Con ganci come useState, useEffect, useContext e altri ancora, Componenti React possono essere costruiti con codice più pulito e riutilizzabile. Inoltre, la possibilità di creare ganci personalizzati consente agli sviluppatori di incapsulare e condividere la logica tra più componenti, favorendo la riusabilità e la modularità del codice. Man mano che React continuerà a evolversi e a introdurre nuove funzionalità, gli agganci svolgeranno senza dubbio un ruolo centrale nello sfruttare appieno il potenziale del framework.

Quindi, sia che si stia lavorando a una piccola applicazione funzionale o a un'applicazione web su larga scala, abbracciare Ganci React migliorerà il vostro flusso di lavoro di sviluppo e aprirà una pletora di possibilità per la creazione di prodotti robusti e ricchi di funzionalità. Applicazioni React .

Fine della Parte 1

Per saperne di più:

L'JavaScript è completamente morto. Un tizio su Internet

Distribuire API GraphQL/MongoDB utilizzando le funzioni Netlify

Come uccidere un progetto con cattive pratiche di codifica

it_ITItalian