ReactJS. Warnung: Es kann keine Aktualisierung des Reaktionsstatus für eine nicht gemountete Komponente durchgeführt werden. Dies ist ein No-Op, aber es zeigt ein Memo an

Guten Tag, Habr!

Alle reaktionsfähigen Entwickler, die sich mit Interaktivität zwischen Rückseite und Vorderseite befassen, treffen sich früher oder später oder haben sich getroffen oder werden auf den folgenden Fehler stoßen:


Es stellt sich buchstäblich so heraus:
Warnung. Der Reaktionsstatus für eine deinstallierte Komponente kann nicht aktualisiert werden. Dies ist keine Operation, weist jedoch auf einen Speicherverlust in Ihrer Anwendung hin. Brechen Sie zum Beheben alle Abonnements und asynchronen Aufgaben in der Funktion useEffect auf.

In der Tat ist alles ganz einfach, Sie müssen nur auf die folgenden Sätze achten:

  1. Statusaktualisierung nicht möglich
  2. eine deinstallierte Komponente;
  3. Kündigen Sie alle Abonnements und asynchronen Aufgaben
  4. useEffect-Bereinigung


Im Herzen von Haken. Geh unter den Schnitt!

Damit:

  1. Alle reaktionsfähigen Programmierer wissen, welche Bedingung (Status) und dass ein solches Update (setState) auch. Das werde ich nicht sein.
  2. . :
    1) ;
    2) ;
    3) ;
    — 3 . .
  3. . - , : . , async/await — .
  4. useEffect. return () => {} useEffect. , - , : .




Machen wir einen Fehler: Nehmen wir an, wir entwickeln eine Website mit einem Upload einer Filmbeschreibung (wir gehen nicht tief in die moviedb-API ein , sondern nehmen einen bestimmten Film als Grundlage). Wir haben zwei Seiten:
Zuhause

Über uns



Links zu beiden Seiten finden Sie im Navigationsbereich, z. B. in der Kopfzeile. Auf der Hauptseite ("Home") gibt es eine Kommunikation mit der Rückseite, um Informationen über den Film hochzuladen.

/src/Pages/HomePage.js
import React, { useState, useEffect } from 'react';

import { MOVIE_DB_GET } from '../config';

const HomePage = () => {
  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(MOVIE_DB_GET);
        const result = await response.json();
        console.log(result, 'result')
      } catch (e) {
        console.error(e.message)
      }
    };

    //  get-     
    fetchData();
  }, []);

  return (
    <main>
      <h2> </h2>
    </main>
  )
};

export default HomePage;


/src/Pages/AboutPage.js

import React from 'react';

const AboutPage = () => {
  return (
    <main>
      <h2> </h2>
      <p>
                
      </p>
    </main>
  )
};

export default AboutPage;


Um Informationen über eine Anforderung anzuzeigen, müssen Informationen für das nachfolgende Rendern in den Status geschrieben werden:

/src/Pages/HomePage.js

import React, { useState, useEffect } from 'react';

import { MOVIE_DB_GET } from '../config';

const HomePage = () => {
  // movie - react-;
  // setMovie -   react-
  const [ movie, setMovie ] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(MOVIE_DB_GET);
        const result = await response.json();
        console.log(result, 'result');
        setMovie(result);
      } catch (e) {
        console.error(e.message)
      }
    };

    //       
    fetchData();
  }, []);

  // descriptionMovie -  ,  view,         movie

  return (
    <main>
      <h2> </h2>
      <p> </p>

      {
        movie ? descriptionMovie() : false
      }
    </main>
  )
};

export default HomePage;


Wir werden den Fehler folgendermaßen reproduzieren: Wir wechseln von einer Route zur anderen, dh wir befinden uns auf der Seite "Über uns", gehen zur Startseite und kehren sofort wieder zur Seite "Über uns" zurück und voila " Kann nicht ausführen ... .. " .

Tatsache ist, dass der Server nicht sofort auf Anforderungen reagiert. Die Asynchronität wird verwendet, um die Anforderung weiterhin parallel zu den erforderlichen Aufgaben abzuspielen. Bei einer schnellen Rückkehr zur Seite "Über uns" wird die Home-Komponente nicht gemountet. Dies bedeutet, dass der Status für diese Komponente zurückgesetzt wird, die asynchrone Anforderung jedoch weiterhin setMovie startet, das nicht mehr vorhanden ist und einen Fehler auslöst. Die beste Lösung besteht darin, die Verwendung von Statusaktualisierungen beim Aufheben der Bereitstellung einer Komponente zu verbieten:

/src/Pages/HomePage.js

import React, { useState, useEffect } from 'react';

import { MOVIE_DB_GET } from '../config';

const HomePage = () => {
  // movie - react-;
  // setMovie -   react-
  const [ movie, setMovie ] = useState(null);

  useEffect(() => {
    let cleanupFunction = false;
    const fetchData = async () => {
      try {
        const response = await fetch(MOVIE_DB_GET);
        const result = await response.json();
        console.log(result, 'result')

        //     ,    
        if(!cleanupFunction) setMovie(result);
      } catch (e) {
        console.error(e.message)
      }
    };

    fetchData();

    //   useEffect
    return () => cleanupFunction = true;
  }, []);

  // descriptionMovie -  ,  view,         movie

  return (
    <main>
      <h2> </h2>
      <p> </p>

      {
        movie ? descriptionMovie() : false
      }
    </main>
  )
};

export default HomePage;


Gesamt:


Der gesamte Quellcode kann hier eingesehen werden: https://gitlab.com/ImaGadzhiev/react-cant-perform

All Articles