it-swarm.com.de

Ist die Verwendung von async componentDidMount () gut?

Ist die Verwendung von componentDidMount() als asynchrone Funktion in React Native empfehlenswert, oder sollte ich dies vermeiden? 

Ich brauche ein paar Informationen von AsyncStorage, wenn die Komponente aktiviert wird, aber die einzige Möglichkeit, dies zu ermöglichen, ist die Funktion componentDidMount() async zu machen. 

async componentDidMount() {
    let auth = await this.getAuth();
    if (auth) 
        this.checkAuth(auth);
}

Gibt es ein Problem damit und gibt es andere Lösungen für dieses Problem?

47
Mirakurun

Beginnen wir damit, auf die Unterschiede hinzuweisen und festzustellen, wie es zu Problemen kommen kann.

Hier ist der Code von async und "sync" componentDidMount() Lebenszyklusmethode:

// This is TypeScript code
componentDidMount(): void { /* do something */ }

async componentDidMount(): Promise<void> {
    /* do something */
    /* You can use "await" here */
}

Wenn ich mir den Code ansehe, kann ich auf folgende Unterschiede hinweisen:

  1. Die Schlüsselwörter async: In TypeScript ist dies lediglich eine Codemarkierung. Es macht 2 Dinge:
    • Erzwinge, dass der Rückgabetyp Promise<void> Anstelle von void ist. Wenn Sie den Rückgabetyp explizit als nicht versprechend angeben (z. B. void), gibt TypeScript einen Fehler aus.
    • Ermöglichen die Verwendung von await Schlüsselwörtern innerhalb der Methode.
  2. Der Rückgabetyp wird von void in Promise<void> Geändert.
    • Das bedeutet, dass Sie dies jetzt tun können:
      async someMethod(): Promise<void> { await componentDidMount(); }
  3. Sie können jetzt das Schlüsselwort await in der Methode verwenden und deren Ausführung vorübergehend anhalten. So was:

    async componentDidMount(): Promise<void> {
        const users = await axios.get<string>("http://localhost:9001/users");
        const questions = await axios.get<string>("http://localhost:9001/questions");
    
        // Sleep for 10 seconds
        await new Promise(resolve => { setTimeout(resolve, 10000); });
    
        // This line of code will be executed after 10+ seconds
        this.setState({users, questions});
        return Promise.resolve();
    }
    

Wie könnten sie nun Probleme verursachen?

  1. Das Schlüsselwort async ist absolut harmlos.
  2. Ich kann mir keine Situation vorstellen, in der Sie die componentDidMount() -Methode aufrufen müssen, sodass der Rückgabetyp Promise<void> Ebenfalls harmlos ist.

    Der Aufruf einer Methode mit dem Rückgabetyp Promise<void> Ohne das Schlüsselwort await unterscheidet sich nicht vom Aufruf einer Methode mit dem Rückgabetyp void.

  3. Da es keine Lebenszyklusmethoden gibt, nachdem componentDidMount() die Ausführung verzögert hat, scheint dies ziemlich sicher zu sein. Aber es gibt ein GOTCHA.

    Angenommen, die obige this.setState({users, questions}); würde nach 10 Sekunden ausgeführt. Mitten in der Verzögerungszeit, eine andere ...

    this.setState({users: newerUsers, questions: newerQuestions});

    ... wurden erfolgreich ausgeführt und das DOM aktualisiert. Das Ergebnis war für Benutzer sichtbar. Die Uhr tickte weiter und es vergingen 10 Sekunden. Das verzögerte this.setState(...) würde dann ausgeführt und das DOM würde erneut aktualisiert, diesmal mit alten Benutzern und alten Fragen. Das Ergebnis wäre auch für Benutzer sichtbar.

=> Die Verwendung von async mit der componentDidMount() -Methode ist ziemlich sicher (ich bin mir nicht sicher, ob es 100% sind). Ich bin ein großer Fan davon und bis jetzt habe ich noch keine Probleme, die mir zu viel Kopfschmerzen bereiten.

100

Ihr Code ist gut und für mich sehr lesbar. Sehen Sie diesen Dale Jeffersons Artikel wo er ein async componentDidMount-Beispiel zeigt und wirklich gut aussieht.

Einige Leute würden jedoch sagen, dass eine Person, die den Code liest, annehmen könnte, dass React etwas mit dem zurückgegebenen Versprechen tut.

Die Interpretation dieses Codes und ob es sich dabei um eine gute Praxis handelt oder nicht, ist also sehr persönlich.

Wenn Sie eine andere Lösung wünschen, können Sie Versprechen verwenden. Zum Beispiel:

componentDidMount() {
    fetch(this.getAuth())
      .then(auth => {
          if (auth) this.checkAuth(auth)
      })
}
6
Tiago Alves

Das asynchrone Laden in ComponentDidMount ist ein empfohlenes Entwurfsmuster , da sich React von früheren Lebenszyklusmethoden (componentWillMount, componentWillReceiveProps, componentWillUpdate) entfernt. und weiter zum asynchronen Rendern.

Dieser Blog-Beitrag ist sehr hilfreich, um zu erklären, warum dies sicher ist, und um Beispiele für das asynchrone Laden in ComponentDidMount bereitzustellen:

https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html

2
DannyMoshe

Ich denke, es ist gut, solange Sie wissen, was Sie tun. Dies kann jedoch verwirrend sein, da async componentDidMount() noch ausgeführt werden kann, nachdem componentWillUnmount ausgeführt wurde und die Komponente ausgehängt wurde. 

Möglicherweise möchten Sie sowohl synchrone als auch asynchrone Aufgaben in componentDidMount starten. Wenn componentDidMount async war, müssten Sie den gesamten synchronen Code vor die erste await setzen. Für jemanden ist es möglicherweise nicht offensichtlich, dass der Code vor der ersten await synchron ausgeführt wird. In diesem Fall würde ich wahrscheinlich componentDidMount synchron halten, aber Sync- und Async-Methoden aufrufen.

Unabhängig davon, ob Sie sich für async componentDidMount() vs sync componentDidMount() beim Aufruf von async-Methoden entscheiden, müssen Sie sicherstellen, dass Sie alle Listener oder asynchronen Methoden bereinigen, die möglicherweise noch ausgeführt werden, wenn die Komponente nicht mehr gemountet wird.

1
dosentmatter

Aktualisieren:

(Mein Build: Reaktion 16, Webpack 4, Babel 7):

Wenn Sie Babel 7 verwenden, werden Sie feststellen:

Mit diesem Muster ...

async componentDidMount() {
    try {
        const res = await fetch(config.discover.url);
        const data = await res.json();
        console.log(data);
    } catch(e) {
        console.error(e);
    }
}

sie werden in den folgenden Fehler geraten ...

Nicht erfasster ReferenceError: regeneratorRuntime ist nicht definiert

In diesem Fall müssen Sie babel-plugin-transform-runtimeinstallieren. _

https://babeljs.io/docs/de/babel-plugin-transform-runtime.html

Wenn Sie das obige Paket (babel-plugin-transform-runtime) nicht installieren möchten, sollten Sie das Promise-Muster beibehalten ...

componentDidMount() {
    fetch(config.discover.url)
    .then(res => res.json())
    .then(data => {
        console.log(data);
    })
    .catch(err => console.error(err));
}
1
Chad

Ich habe einige Nachforschungen angestellt und einen wichtigen Unterschied festgestellt: React verarbeitet keine Fehler aus asynchronen Lebenszyklusmethoden.

Also, wenn Sie so etwas schreiben:

componentDidMount()
{
    throw new Error('I crashed!');
}

dann wird Ihr Fehler von der Fehlergrenze abgefangen, und Sie können ihn verarbeiten und eine anmutige Meldung anzeigen.

Wenn wir den Code so ändern:

async componentDidMount()
{
    throw new Error('I crashed!');
}

was dazu äquivalent ist:

componentDidMount()
{
    return Promise.reject(new Error('I crashed!'));
}

dann wird dein Fehler lautlos verschluckt . Schande über dich, Reagiere ...

Wie verarbeiten wir also Fehler als? Der einzige Weg scheint expliziter Fang zu sein:

async componentDidMount()
{
    try
    {
         await myAsyncFunction();
    }
    catch(error)
    {
        //...
    }
}

oder so:

componentDidMount()
{
    myAsyncFunction()
    .catch(()=>
    {
        //...
    });
}

Wenn wir unseren Fehler noch an der Fehlergrenze reich haben wollen, kann ich mir folgenden Trick überlegen:

  1. Beheben Sie den Fehler und veranlassen Sie den Fehlerbehandler, den Komponentenzustand zu ändern
  2. Wenn der Status einen Fehler anzeigt, werfen Sie ihn aus der Methode render.

Beispiel:

class BuggyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
  }

  buggyAsyncfunction(){ return Promise.reject(new Error('I crashed async!'));}

  async componentDidMount() {
    try
    {
      await this.buggyAsyncfunction();
    }
    catch(error)
    {
        this.setState({error: error});
    }
  }

  render() {
    if(this.state.error)
        throw this.state.error;

    return <h1>I am OK</h1>;
  }
}
1
C-F

Wenn Sie componentDidMount ohne das Schlüsselwort async verwenden, sagt das Dokument Folgendes:

Sie können setState () sofort in componentDidMount () aufrufen. Es wird ein zusätzliches Rendering ausgelöst, es erfolgt jedoch, bevor der Browser den Bildschirm aktualisiert.

Wenn Sie async componentDidMount verwenden, verlieren Sie diese Fähigkeit: Nach dem Aktualisieren des Browsers erfolgt ein erneutes Rendern. Wenn Sie jedoch über async nachdenken, beispielsweise Daten abrufen, können Sie nicht vermeiden, dass der Browser den Bildschirm zweimal aktualisiert. In einer anderen Welt ist es nicht möglich, componentDidMount vor dem Browser-Update des Bildschirms zu PAUSE

0
Lu Tran