UseEffect запускает функцию дополнительный раз вместо одного раза для каждого оператора if.Javascript

Форум по Javascript
Ответить
Anonymous
 UseEffect запускает функцию дополнительный раз вместо одного раза для каждого оператора if.

Сообщение Anonymous »

У меня есть модальное окно. Это модальное окно открывается после того, как пользователь загружает CSV-файл. Затем они могут внести изменения в записи или удалить их. Пользователь может подтвердить и продолжить (перейти на следующую страницу, модальное закрытие) или загрузить новый файл (модальное закрытие, остаться на той же странице). Однако, если они внесут какие-либо изменения, после этих двух появится новая кнопка: «Загрузить обновленный CSV».
В настоящее время в моем модальном окне я реализую захват фокуса в целях доступности. Моя ловушка фокуса не позволит пользователю нажимать вкладку за пределами модального окна - если он нажимает вкладку на последнем элементе, он фокусируется на первом, а сдвиг табуляции на первом - на последнем. Вот где моя проблема была впервые замечена.
В моем функциональном компоненте модального окна есть useEffect. Этот useEffect определит внесение изменений и вызовет повторный рендеринг (с использованием специального перехватчика), а затем получит ссылку на все интерактивные элементы. Затем это передается в функцию focusTrap.
Пользовательский хук useIsMount (используется для проверки того, находится ли DOM при первом или втором рендеринге, в случае, если элементы не готовы к использованию):

Код: Выделить всё

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

Код: Выделить всё

useEffect
что (может быть) вызывает проблему:

Код: Выделить всё

const isMount = useIsMount();

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

Код: Выделить всё

!isMount
используется здесь, чтобы убедиться, что весь контент был отображен перед захватом элементов. Я не использую массив зависимостей, чтобы он всегда запускал useEffect при повторной отрисовке.
Моя функция focusTrap, которая до сих пор меня не подводила:

Код: Выделить всё

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);
};
};
При рендеринге модального окна все кнопки находятся нормально и без проблем. Однако когда пользователь вносит изменения, useEffect запускается снова, и функция focusTrap вызывается снова. Каждое дополнительное изменение приведет к тому, что focusTrap запустит дополнительный экземпляр, но с другим списком focusableElements для каждого экземпляра. При первом редактировании кнопка «Загрузить обновленный CSV» отображается условно. Он отображается в console.log для focusableElements, но только при втором запуске focusTrap. Это приводит к тому, что первый запуск имеет приоритет, игнорируя новую кнопку и снова фокусируясь на первом.
Изображение

Я пробовал:
  • Добавление пустого массив зависимостей (не улавливает повторную отрисовку изменения содержимого, не обнаруживает кнопку «Загрузить»)
  • Добавление массива зависимостей для isMount и totalEdits/

    Код: Выделить всё

    totalDeletes
    (отслеживайте объемы редактирования/удаления для отображения кнопки «Загрузить»), но я все равно вызываю focusTrap, поскольку мне нужен оператор if, чтобы определить, есть ли изменения

    Код: Выделить всё

    if (totalEdits > 0 || totalDeletes > 0) {
    buttonsElement && focusTrap(buttonsElement, onClose);
    }
    
  • Куча других вещей, которые я, честно говоря, даже не могу сейчас вспомнить. Либо ловушка фокуса выйдет из модального окна (но обнаружит новую кнопку!), либо кнопка все еще не фокусируется.
Возможно, новый addEventListener добавляется каждый раз, когда запускается focusTrap, потому что всякий раз, когда я нажимаю Tab, handleTabKeyPress будет запускаться еще один раз для каждого внесенного изменения (т.е. 3 изменений/удалений, сделанных в CSV) table - handleTabKeyPress запускается 4 раза одновременно, и я записываю что-то в консоль)
Можно ли каким-то образом завершить работу функции, прежде чем она запустится снова?
Наконец, если я условно визуализирую эту кнопку где-то, что она не является последним элементом, она фокусируется нормально (как перед кнопкой «Подтвердить»). Однако focusTrap по-прежнему запускается несколько раз, и это нехорошо.

Подробнее здесь: https://stackoverflow.com/questions/798 ... -if-statem
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»