#javascript #reactjs
Вопрос:
Я видел подобные вопросы в SO, но не смог определить проблему, с которой я сталкиваюсь.
У меня есть переменная useState, которую я установил в useEffect при первой загрузке. Затем, гораздо позже, происходит событие, и в нем я проверяю значение переменной, и это всегда пустой массив []. Однако я добавил второй эффект использования для отслеживания изменений в моей переменной состояния, и я не вижу, где она опустошается. Вот несколько кодов, чтобы подчеркнуть мою проблему:
import React, { useState, useEffect } from "react";
import { DragAndDrop } from "../components";
const AddKidPage = () => {
const [files, setFiles] = useState([]);
useEffect(() => {
var f = [
"nice.pdf",
"verycool.jpg",
"amazing.png",
"goodstuff.mp3",
"thankyou.doc",
];
setFiles(f);
}, []);
useEffect(() => {
console.log(files);
}, [files]);
const handleDrop = (newFiles) => {
let fileList = files;
// HERE FILES = []
for (var i = 0; i < newFiles.length; i ) {
if (!newFiles[i].name) return;
fileList.push(newFiles[i].name);
}
setFiles(fileList);
};
return (
<main>
<DragAndDrop handleDrop={handleDrop}>
<div style={{ height: 300, width: 250 }}>
{files.map((file, i) => (
<div key={i}>{file}</div>
))}
</div>
</DragAndDrop>
</main>
);
};
export default AddKidPage;
У меня есть 1 консоль.войдите в систему с эффектом отслеживания файлов. Вот вывод, когда компонент монтируется:
[]
[«хороший.pdf», «verycool.jpg», «удивительный.png», «goodstuff.mp3», «thankyou.doc»]
Это имеет смысл — я инициализирую массив как пустой, затем я немедленно заполняю его значениями, которые затем запускают второй вывод. Однако вот вывод ПОСЛЕ того, как я удаляю файл (это приводит к выполнению handleDrop ()):
[«Новый файл.png»]
Как вы можете видеть, ВСЕ остальные ценности были уничтожены. Мой комментарий в коде «ЗДЕСЬ ФАЙЛЫ = []» демонстрирует, где состояние использования файлов по-прежнему пусто, хотя мой вывод показывает, что оно было заполнено. Эффект использования никогда не выводит пустой массив во второй раз, так где же он опустошается? Я неправильно получаю значение? Мы высоко ценим любую помощь в решении этой загадки. Я решил не показывать код для компонента DragAndDrop, но он кажется надежным и вызывает метод handleDrop в нужное время и с правильными значениями.
Редактировать:
Хотя DragAndDrop кажется надежным, это может быть какой-то проблемой с тем, как я вызываю переданную функцию… или мое использование {детей}. Я не уверен. Итак, вот код для DragAndDrop, который завершает этот компонент.
import React, { useState, useEffect } from "react";
import styled from "styled-components";
const DragAndDrop = ({ handleDrop: externalDrop, children }) => {
const [drag, setDrag] = useState(false);
const [dragCounter, setDragCounter] = useState(0);
const handleDrag = (e) => {
e.preventDefault();
e.stopPropagation();
};
const handleDragIn = (e) => {
e.preventDefault();
e.stopPropagation();
setDragCounter(dragCounter 1);
if (e.dataTransfer.items amp;amp; e.dataTransfer.items.length > 0) {
setDrag(true);
}
};
const handleDragOut = (e) => {
e.preventDefault();
e.stopPropagation();
setDragCounter(dragCounter - 1);
if (dragCounter - 1 === 0) {
setDrag(false);
}
};
const handleDrop = (e) => {
e.preventDefault();
e.stopPropagation();
setDrag(false);
if (e.dataTransfer.files amp;amp; e.dataTransfer.files.length > 0) {
externalDrop(e.dataTransfer.files);
e.dataTransfer.clearData();
setDragCounter(0);
}
};
useEffect(() => {
var div = document.getElementById("draganddrop-wrapper");
div.addEventListener("dragenter", handleDragIn);
div.addEventListener("dragleave", handleDragOut);
div.addEventListener("dragover", handleDrag);
div.addEventListener("drop", handleDrop);
return () => {
div.removeEventListener("dragenter", handleDragIn);
div.removeEventListener("dragleave", handleDragOut);
div.removeEventListener("dragover", handleDrag);
div.removeEventListener("drop", handleDrop);
};
}, []);
return (
<Wrapper id="draganddrop-wrapper">
{drag amp;amp; (
<div className="drag-hover">
<div className="drag-overlay">
<div>drop here</div>
</div>
</div>
)}
{children}
</Wrapper>
);
};
const Wrapper = styled.div`
display: inline-block;
position: relative;
.drag-hover {
border: dashed grey 4px;
background: rgba(255, 255, 255, 0.8);
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 9999;
.drag-overlay {
position: absolute;
top: 50%;
right: 0;
left: 0;
text-align: center;
color: grey;
font-size: 36px;
}
}
`;
export default DragAndDrop;
Ответ №1:
Это потому, что вы мутируете files
переменную, а не клонируете ее.
Изменить
let fileList = files;
Для
const fileList = [...files];
Обновить
const handleDrop = useCallback((newFile) => {
if (newFile.type === "image/png") {
setFile(newFile.name);
}
}, []);
Комментарии:
1. Спасибо за предложение. Я попробовал это, и результаты те же. Я добавил этот код: const FileList = […файлы]; console.log(список файлов); и вывод, который я получаю, [].
2. Попробуйте изменить
const fileList = [...files];
наlet fileList = [...files];
3. К сожалению, то же самое происходит и с let.
4. Я изменил свой вопрос, включив в него другой компонент. Я не уверен, виноват ли он, но решил добавить это.
5. @BrianLegg Вы хотите сказать, что при первом
handledrop
вызове после монтирования компонентаfiles
массивconsole.log
в// HERE...
комментарии такой же пустой?DragAndDrop
Компонент не будет иметь значения, так как он напрямую не взаимодействует сfiles
массивом. Можете ли вы предоставить образец своего кода в codesandbox?