Ich bin neu in der Verwendung von React, daher ist dies möglicherweise sehr einfach zu erreichen, aber ich kann es nicht selbst herausfinden, obwohl ich einige Nachforschungen angestellt habe. Vergib mir, wenn das zu dumm ist.
Kontext
Ich verwende Inertia.js mit den Adaptern Laravel (Backend) und React (Frontend). Wenn Sie Trägheit nicht kennen, ist es im Grunde:
Mit Inertia.js können Sie schnell moderne einseitige React-, Vue- und Svelte-Apps mit klassischem serverseitigem Routing und Controllern erstellen.
Problem
Ich mache eine einfache Anmeldeseite mit einem Formular, das beim Senden eine POST-Anforderung zum Laden der nächsten Seite ausführt. Es scheint gut zu funktionieren, aber auf anderen Seiten zeigt die Konsole die folgende Warnung:
Warnung: Es kann keine Aktualisierung des Reaktionsstatus für eine nicht gemountete Komponente durchgeführt werden. Dies ist ein No-Op, weist jedoch auf einen Speicherverlust in Ihrer Anwendung hin. Brechen Sie zum Beheben alle Abonnements und asynchronen Aufgaben in einer useEffect-Bereinigungsfunktion ab.
im Login (erstellt von Inertia)
Der zugehörige Code (ich habe ihn vereinfacht, um irrelevante Zeilen zu vermeiden):
import React, { useEffect, useState } from 'react'
import Layout from "../../Layouts/Auth";
{/** other imports */}
const login = (props) => {
const { errors } = usePage();
const [values, setValues] = useState({email: '', password: '',});
const [loading, setLoading] = useState(false);
function handleSubmit(e) {
e.preventDefault();
setLoading(true);
Inertia.post(window.route('login.attempt'), values)
.then(() => {
setLoading(false); // Warning : memory leaks during the state update on the unmounted component <--------
})
}
return (
<Layout title="Access to the system">
<div>
<form action={handleSubmit}>
{/*the login form*/}
<button type="submit">Access</button>
</form>
</div>
</Layout>
);
};
export default login;
Jetzt weiß ich, dass ich eine Bereinigungsfunktion ausführen muss, da das Versprechen der Anforderung das ist, was diese Warnung generiert. Ich weiß, dass ich es verwenden sollte, useEffect
aber ich weiß nicht, wie ich es in diesem Fall anwenden soll. Ich habe ein Beispiel gesehen, wenn sich ein Wert ändert, aber wie geht das bei einem Aufruf dieser Art?
Danke im Voraus.
Aktualisieren
Wie gewünscht, der vollständige Code dieser Komponente:
import React, { useState } from 'react'
import Layout from "../../Layouts/Auth";
import { usePage } from '@inertiajs/inertia-react'
import { Inertia } from "@inertiajs/inertia";
import LoadingButton from "../../Shared/LoadingButton";
const login = (props) => {
const { errors } = usePage();
const [values, setValues] = useState({email: '', password: '',});
const [loading, setLoading] = useState(false);
function handleChange(e) {
const key = e.target.id;
const value = e.target.value;
setValues(values => ({
...values,
[key]: value,
}))
}
function handleSubmit(e) {
e.preventDefault();
setLoading(true);
Inertia.post(window.route('login.attempt'), values)
.then(() => {
setLoading(false);
})
}
return (
<Layout title="Inicia sesión">
<div className="w-full flex items-center justify-center">
<div className="w-full max-w-5xl flex justify-center items-start z-10 font-sans text-sm">
<div className="w-2/3 text-white mt-6 mr-16">
<div className="h-16 mb-2 flex items-center">
<span className="uppercase font-bold ml-3 text-lg hidden xl:block">
Optima spark
</span>
</div>
<h1 className="text-5xl leading-tight pb-4">
Vuelve inteligente tus operaciones
</h1>
<p className="text-lg">
Recoge data de tus instalaciones de forma automatizada; accede a información histórica y en tiempo real
para que puedas analizar y tomar mejores decisiones para tu negocio.
</p>
<button type="submit" className="bg-yellow-600 w-40 hover:bg-blue-dark text-white font-semibold py-2 px-4 rounded mt-8 shadow-md">
Más información
</button>
</div>
<div className="w-1/3 flex flex-col">
<div className="bg-white text-gray-700 shadow-md rounded rounded-lg px-8 pt-6 pb-8 mb-4 flex flex-col">
<div className="w-full rounded-lg h-16 flex items-center justify-center">
<span className="uppercase font-bold text-lg">Acceder</span>
</div>
<form onSubmit={handleSubmit} className={`relative ${loading ? 'invisible' : 'visible'}`}>
<div className="mb-4">
<label className="block text-gray-700 text-sm font-semibold mb-2" htmlFor="email">
Email
</label>
<input
id="email"
type="text"
className=" appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 outline-none focus:border-1 focus:border-yellow-500"
placeholder="Introduce tu e-mail.."
name="email"
value={values.email}
onChange={handleChange}
/>
{errors.email && <p className="text-red-500 text-xs italic">{ errors.email[0] }</p>}
</div>
<div className="mb-6">
<label className="block text-gray-700 text-sm font-semibold mb-2" htmlFor="password">
Contraseña
</label>
<input
className=" appearance-none border border-red rounded w-full py-2 px-3 text-gray-700 mb-3 outline-none focus:border-1 focus:border-yellow-500"
id="password"
name="password"
type="password"
placeholder="*********"
value={values.password}
onChange={handleChange}
/>
{errors.password && <p className="text-red-500 text-xs italic">{ errors.password[0] }</p>}
</div>
<div className="flex flex-col items-start justify-between">
<LoadingButton loading={loading} label='Iniciar sesión' />
<a className="font-semibold text-sm text-blue hover:text-blue-700 mt-4"
href="#">
<u>Olvidé mi contraseña</u>
</a>
</div>
<div
className={`absolute top-0 left-0 right-0 bottom-0 flex items-center justify-center ${!loading ? 'invisible' : 'visible'}`}
>
<div className="lds-ellipsis">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</form>
</div>
<div className="w-full flex justify-center">
<a href="https://optimaee.com">
</a>
</div>
</div>
</div>
</div>
</Layout>
);
};
export default login;
quelle
.then(() => {})
?Antworten:
Da es sich um den asynchronen Versprechungsaufruf handelt, müssen Sie eine veränderbare Referenzvariable (mit useRef) verwenden , um bereits nicht gemountete Komponenten auf die nächste Behandlung der asynchronen Antwort zu überprüfen (um Speicherlecks zu vermeiden):
Zwei Reaktionshaken, die Sie in diesem Fall verwenden sollten:
useRef
unduseEffect
.Mit
useRef
, beispielsweise die veränderliche Variable_isMounted
ist , immer an der gleichen Referenz im Speicher zeigt (nicht eine lokale Variable)Beispiel:
Lassen Sie mich Ihnen bei der gleichen Gelegenheit weitere Informationen zu den hier verwendeten React Hooks erläutern. Außerdem werde ich React Hooks in Functional Component (die Version React> 16.8) mit LifeCycle in Class Component vergleichen.
1) Das Standardverhalten von useEffect wird sowohl nach dem ersten Rendern (wie ComponentDidMount) als auch nach jedem Update-Rendering (wie ComponentDidUpdate) ausgeführt, wenn Sie keine Abhängigkeiten haben. Es ist wie es ist :
useEffect(fnc);
2) Wenn Sie eine Reihe von Abhängigkeiten für useEffect angeben, ändert sich der Lebenszyklus. In diesem Beispiel: useEffect wird nach dem ersten Rendern einmal aufgerufen und jedes Mal, wenn sich die Anzahl ändert
3) useEffect wird nach dem ersten Rendern nur einmal ausgeführt (wie ComponentDidMount), wenn Sie ein leeres Array für die Abhängigkeit . Es ist wie es ist :
useEffect(fnc, []);
4) Um Ressourcenlecks zu vermeiden, muss alles entsorgt werden, wenn der Lebenszyklus eines Hooks endet (wie bei ComponentWillUnmount) . Beispielsweise wird mit dem leeren Abhängigkeitsarray die zurückgegebene Funktion aufgerufen, nachdem die Komponenten ausgehängt wurden. Es ist wie es ist :
Beispiel: Bei der obigen Frage können wir hier keine lokale Variable verwenden, da diese bei jedem Update-Rendering verloren geht und neu initiiert wird.
Mit der Kombination von useRef und useEffect können wir also Speicherlecks vollständig bereinigen.
Die guten Links, über die Sie mehr über die React Hooks lesen können, sind:
[DE] https://medium.com/@sdolidze/the-iceberg-of-react-hooks-af0b588f43fb
[FR] https://blog.soat.fr/2019/11/react-hooks-par-lexemple/
quelle
Sie können die Methode 'cancelActiveVisits' verwenden
Inertia
, um den aktiven Hookvisit
für dieuseEffect
Bereinigung abzubrechen .Mit diesem Anruf wird der aktive
visit
Vorgang abgebrochen und der Status wird nicht aktualisiert.Wenn die
Inertia
Anforderung abgebrochen wird, wird eine leere Antwort zurückgegeben, sodass Sie eine zusätzliche Prüfung hinzufügen müssen, um die leere Antwort zu verarbeiten. Fügen Sie auch add catch catch-Block hinzu, um mögliche Fehler zu behandeln.Alternativer Weg (Problemumgehung)
Sie können verwenden
useRef
, um den Status der Komponente zu speichern, und auf dieser Grundlage können Sie die aktualisierenstate
.Problem:
Der Warring wird angezeigt, weil
handleSubmit
versucht wird, den Status der Komponente zu aktualisieren, obwohl die Komponente vom Dom nicht bereitgestellt wurde.Lösung:
Setzen Sie ein Flag, um den Status von zu speichern.
component
Wenn dascomponent
ist,mounted
ist derflag
Werttrue
und wenn dascomponent
ist, istunmounted
der Flag-Wert falsch. Auf dieser Grundlage können wir das aktualisierenstate
. Für den Flaggenstatus können wiruseRef
eine Referenz halten.Und dann
useEffect
können wir in der Bereinigungsfunktion das Flag auf setzenfalse.
useEffecr Bereinigungsfunktion
Beispiel:
Und in handleSubmit können wir prüfen, ob die Komponente gemountet ist oder nicht, und den Status basierend darauf aktualisieren.
In else setzen Sie den
_componentStatus
Wert auf null, um Speicherverluste zu vermeiden.quelle
ajaxCall
innen tröstenuseEffect
. und sehen, was der Wert istundefined
. Ich habe es kurz nach demreturn () => {