Come chiamare la funzione di caricamento con React useEffect solo una volta


210

Il hook useEffect React eseguirà la funzione passata su ogni modifica. Questo può essere ottimizzato per lasciarlo chiamare solo quando cambiano le proprietà desiderate.

Cosa succede se desidero chiamare una funzione di inizializzazione componentDidMounte non richiamarla di nuovo sulle modifiche? Diciamo che voglio caricare un'entità, ma la funzione di caricamento non ha bisogno di alcun dato dal componente. Come possiamo farlo usando il useEffectgancio?

class MyComponent extends React.PureComponent {
    componentDidMount() {
        loadDataOnlyOnce();
    }
    render() { ... }
}

Con i ganci questo potrebbe apparire così:

function MyComponent() {
    useEffect(() => {
        loadDataOnlyOnce(); // this will fire on every change :(
    }, [...???]);
    return (...);
}

Risposte:


397

Se si desidera eseguire solo la funzione assegnata useEffectdopo il rendering iniziale, è possibile assegnargli un array vuoto come secondo argomento.

function MyComponent() {
  useEffect(() => {
    loadDataOnlyOnce();
  }, []);

  return <div> {/* ... */} </div>;
}

28
In alternativa, se ci sono parametri che usi per recuperare i dati (ad es. Un ID utente) potresti passare l'ID utente in quell'array e se cambia il componente recupererà i dati. Molti casi d'uso funzioneranno in questo modo.
Trixn,

4
sì ... ulteriori informazioni sul salto sono documentate qui: reazionejs.org/docs/…
Melounek,

Questa sembra la risposta più semplice, ma ESLint si lamenta ... vedi altre risposte su questa discussione stackoverflow.com/a/56767883/1550587
Simon Hutchison

Basta passare loadDataOnlyOnce nell'array delle dipendenze. Funziona?
jpmarks

88

TL; DR

useEffect(yourCallback, []) - attiverà la richiamata solo dopo il primo rendering.

Spiegazione dettagliata

useEffectviene eseguito per impostazione predefinita dopo ogni rendering del componente (causando così un effetto).

Al momento del posizionamento useEffect il componente, si dice a React che si desidera eseguire il callback come effetto. React eseguirà l'effetto dopo il rendering e dopo aver eseguito gli aggiornamenti DOM.

Se si passa solo un callback, il callback verrà eseguito dopo ogni rendering.

Se passa un secondo argomento (array), React eseguirà il callback dopo il primo rendering e ogni volta che uno degli elementi dell'array viene modificato. ad esempio durante il posizionamento useEffect(() => console.log('hello'), [someVar, someOtherVar]): il callback verrà eseguito dopo il primo rendering e dopo qualsiasi rendering di quello di someVarosomeOtherVar viene modificato.

Passando il secondo argomento a un array vuoto, React confronterà dopo ogni rendering l'array e non vedrà nulla che sia stato modificato, chiamando così il callback solo dopo il primo rendering.


69

hook hook UseMountEffect

L'esecuzione di una funzione solo una volta dopo il montaggio dei componenti è un modello così comune che giustifica un suo hook che nasconde i dettagli di implementazione.

const useMountEffect = (fun) => useEffect(fun, [])

Usalo in qualsiasi componente funzionale.

function MyComponent() {
    useMountEffect(function) // function will run only once after it has mounted. 
    return <div>...</div>;
}

Informazioni sul hook useMountEffect

Quando si utilizza useEffectcon un secondo argomento di matrice, React eseguirà il callback dopo il montaggio (rendering iniziale) e dopo che i valori nella matrice saranno cambiati. Poiché passiamo un array vuoto, verrà eseguito solo dopo il montaggio.


19
Preferisco di gran lunga la tua risposta, poiché la regola ESLint "reazioni-ganci / deps esaustivi" fallirà sempre su elenchi di dipendenze vuoti. E ad esempio il famoso modello create-reagire-app imporrà quella regola.
Dynalon,

1
Totalmente d'accordo con @Dynalon. Questa dovrebbe essere la soluzione accettata in quanto non interferisce con la regola
ESLint

Grazie @Dynalon e Mikado68 :-). La decisione è un privilegio dell'OP. Sono stato informato dei tuoi commenti, ma l'OP no. Puoi suggerirglielo commentando direttamente la domanda.
Ben Carp

2
Ora puoi usarlo useMountquando la tua funzione effetto ha bisogno di qualcosa dagli oggetti di scena ma non deve mai essere eseguita di nuovo anche se quel valore cambia senza avviso linter: useEffect(()=>console.log(props.val),[])avrà un avviso di dipendenza mancante ma useMount(()=>console.log(props.val))non causerà un avviso ma "funziona". Non sono sicuro se ci sarà un problema con la modalità simultanea.
HMR

1
Mi piace questo :) Stesso motivo del precedente stato; la regola ESLint non si lamenterà di questo, inoltre il nome è più facile da capire di un array vuoto
Frexuz

20

Passa un array vuoto come secondo argomento a useEffect. Questo effettivamente dice a React, citando i documenti :

Questo dice a React che il tuo effetto non dipende da alcun valore proveniente da oggetti di scena o stato, quindi non deve mai essere eseguito nuovamente.

Ecco uno snippet che puoi eseguire per mostrare che funziona:

function App() {
  const [user, setUser] = React.useState(null);

  React.useEffect(() => {
    fetch('https://randomuser.me/api/')
      .then(results => results.json())
      .then(data => {
        setUser(data.results[0]);
      });
  }, []); // Pass empty array to only run once on mount.
  
  return <div>
    {user ? user.name.first : 'Loading...'}
  </div>;
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>


4

Mi piace definire una mountfunzione, inganna EsLint allo stesso modo useMounte la trovo più autoesplicativa.

const mount = () => {
  console.log('mounted')
  // ...

  const unmount = () => {
    console.log('unmounted')
    // ...
  }
  return unmount
}
useEffect(mount, [])

-2

Il trucco è che useEffect accetta un secondo parametro.

Il secondo parametro è un array di variabili che il componente controllerà per assicurarsi che sia cambiato prima del nuovo rendering. Puoi mettere qualsiasi frammento di oggetti di scena e dichiarare qui che vuoi verificare.

Oppure, non mettere nulla:

import React, { useEffect } from 'react';

function App() {
  useEffect(() => {

    // Run! Like go get some data from an API.

  }, []); //Empty array as second argument

  return (
    <div>
      {/* Do something with data. */}
    </div>
  );
}

Ciò garantirà che useEffect venga eseguito una sola volta.

Nota dai documenti:

Se si utilizza questa ottimizzazione, assicurarsi che l'array includa tutti i valori dell'ambito del componente (come oggetti di scena e stato) che cambiano nel tempo e che vengono utilizzati dall'effetto. In caso contrario, il codice farà riferimento a valori non aggiornati dei rendering precedenti.


4
Se stai letteralmente copiando / incollando dai trucchi CSS, il minimo che puoi fare è accreditare la tua fonte. css-tricks.com/run-useeffect-only-once
burtyish
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.