UseEffect führt eine Funktion ein weiteres Mal statt einmal pro if-Anweisung ausJavaScript

Javascript-Forum
Anonymous
 UseEffect führt eine Funktion ein weiteres Mal statt einmal pro if-Anweisung aus

Post by Anonymous »

Ich habe ein Modal. Dieses Modal wird geöffnet, nachdem ein Benutzer eine CSV-Datei hochgeladen hat. Anschließend können Sie Änderungen an den Einträgen vornehmen oder diese löschen. Der Benutzer kann Bestätigen und fortfahren (zur nächsten Seite gehen, modales Schließen) oder Neue Datei hochladen (modales Schließen, auf derselben Seite bleiben). Wenn sie jedoch Änderungen vornehmen, wird nach diesen beiden eine neue Schaltfläche angezeigt: Aktualisierte CSV herunterladen
Derzeit implementieren wir auf meinem Modal Focus Trapping aus Gründen der Barrierefreiheit. Meine Fokusfalle verhindert, dass der Benutzer außerhalb des Modals mit der Tabulatortaste bewegt. Wenn er beim letzten Element die Tabulatortaste drückt, wird das erste fokussiert, und durch Umschalten der Tabulatortaste beim ersten wird das letzte fokussiert. Hier ist mein Problem zum ersten Mal aufgefallen.
In meiner Funktionskomponente für das Modal habe ich einen useEffect. Dieser useEffect erkennt, wenn Änderungen vorgenommen werden, führt zu einem erneuten Rendern (unter Verwendung eines benutzerdefinierten Hooks) und greift dann auf einen Verweis aller interagierbaren Elemente zu. Dies wird dann an eine Funktion namens focusTrap übergeben.
Benutzerdefinierter Hook useIsMount (wird zur Überprüfung verwendet, ob sich DOM beim ersten oder zweiten Rendern befindet, falls Elemente nicht zum Referenzieren bereit sind):

Code: Select all

export const useIsMount = () => {
const isMountRef = useRef(true);
useEffect(() => {
isMountRef.current = false;
}, []);
return isMountRef.current;
};

Code: Select all

useEffect
, der das Problem verursachen könnte:

Code: Select all

const isMount = useIsMount();

useEffect(() => {
if (!isMount) {
const buttonsElement = buttonsRef?.current;
buttonsElement && focusTrap(buttonsElement, onClose);
}
});

Code: Select all

!isMount
wird hier verwendet, um sicherzustellen, dass der gesamte Inhalt gerendert wurde, bevor Elemente erfasst werden. Ich verwende kein Abhängigkeitsarray, sodass beim erneuten Rendern immer useEffect ausgeführt wird.
Meine focusTrap-Funktion, die mich bisher noch nicht im Stich gelassen hat:

Code: Select all

export const focusTrap = (modalElement, onClose) => {
const focusableElements = modalElement.querySelectorAll(
'button, [href], input, checkbox, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];

const handleTabKeyPress = (event) => {
if (event.key === "Tab") {
if (event.shiftKey && document.activeElement === firstElement) {
event.preventDefault();
lastElement.focus();
} else if (!event.shiftKey && document.activeElement === lastElement) {
event.preventDefault();
firstElement.focus();
}
}
};

const handleEscapeKeyPress = (event) => {
if (event.key === "Escape") {
onClose();
}
};

modalElement.addEventListener("keydown", handleTabKeyPress, true);
modalElement.addEventListener("keydown", handleEscapeKeyPress);

return () => {
modalElement.removeEventListener("keydown", handleTabKeyPress, true);
modalElement.removeEventListener("keydown", handleEscapeKeyPress);
};
};
Beim modalen Rendern werden alle Schaltflächen einwandfrei und ohne Probleme gefunden. Wenn der Benutzer jedoch eine Änderung vornimmt, wird useEffect erneut ausgeführt und die Funktion focusTrap wird erneut aufgerufen. Jede weitere Änderung führt dazu, dass focusTrap eine zusätzliche Instanz ausführt, jedoch mit einer anderen Liste von focusableElements für jede Instanz. Wenn die erste Bearbeitung vorgenommen wird, wird die Schaltfläche „Aktualisierte CSV herunterladen“ bedingt gerendert. Es wird in den console.logs für focusableElements angezeigt, aber nur im zweiten Lauf von focusTrap. Dies führt dazu, dass die erste Ausführung Priorität hat, die neue Schaltfläche ignoriert und sich wieder auf die erste konzentriert.
Image

Ich habe versucht:
  • Leeres Abhängigkeitsarray hinzufügen (Fängt das erneute Rendern von Inhaltsänderungen nicht ab, erkennt die Download-Schaltfläche nicht)
  • Hinzufügen eines Abhängigkeitsarrays für isMount und totalEdits/

    Code: Select all

    totalDeletes
    (Verfolgen Sie die Bearbeitungs-/Löschbeträge, um die Download-Schaltfläche zu rendern), aber ich rufe trotzdem focusTrap auf, da ich eine if-Anweisung benötige, um festzustellen, ob es Änderungen gibt

    Code: Select all

    if (totalEdits > 0 || totalDeletes > 0) {
    buttonsElement && focusTrap(buttonsElement, onClose);
    }
    
  • Eine Menge anderer Dinge, an die ich mich zu diesem Zeitpunkt ehrlich gesagt noch nicht einmal erinnern kann. Entweder schlägt die Fokusfalle fehl und entkommt dem Modal (erkennt aber die neue Schaltfläche!) oder die Schaltfläche ist immer noch nicht fokussierbar
Es kann sein, dass jedes Mal, wenn focusTrap ausgeführt wird, ein neuer addEventListener hinzugefügt wird, denn wenn ich die Tabulatortaste drücke, wird handleTabKeyPress für jede vorgenommene Änderung ein weiteres Mal ausgeführt (d. h. 3 Änderungen/Löschungen an der CSV-Tabelle - handleTabKeyPress wird viermal gleichzeitig ausgeführt und ich protokolliere etwas in der Konsole)
Wäre es irgendwie möglich, eine laufende Funktion zu beenden, bevor sie erneut ausgeführt wird?
Wenn ich diese Schaltfläche schließlich an einer bedingten Stelle rendere, an der sie nicht das letzte Element ist, ist sie gut fokussiert (wie vor der Schaltfläche „Bestätigen“). FocusTrap wird jedoch immer noch mehrmals ausgeführt, und das ist nicht gut.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post