#javascript #reactjs #react-hooks #onchange #custom-component
Вопрос:
Вопрос: Когда props.files
консоль регистрируется (посмотрите код ниже, чтобы увидеть, где он регистрируется), он работает в первый раз. Но, когда я выбираю новый набор файлов, консоль больше никогда ничего не регистрирует, если я не перезагружу страницу и не начну все сначала. Что я здесь делаю не так?
Информация о моем коде:
Я использую компоненты формы React Bootstrap (прокрутите до «Ввод файла») для следующего пользовательского компонента (т.е. Form.Group, Form.Label, Form.Control). Код сильно упрощен для наглядности:
const UploadFile = (props) => {
// stuff here
console.log(props.files);
const filesFunction = (filesInput) {
// do stuff with filesInput
}
return {
<Form.Group controlId="formFileMultiple" className="mb-3">
<Form.Label> Files </Form.Label>
<Form.Control
type="file" multiple
onChange={props.handleFilesChange}
onChange={filesFunction(files)}
name="files"
key="files"
/>
</Form.Group>
}
В родительском у меня есть экземпляр пользовательского компонента uploadFile как такового:
const [listOfFiles, setListOfFiles] = useState([]);
const handleFilesChange = (e) {
setListOfFiles(e.target.files);
}
<UploadFile
handleFilesChange = { e => handleFilesChange(e) }
files = {listOfFiles}
/>
Комментарии:
1. если
handleFilesChange
не работает, вы должны включить этот код в вопрос. вы показали нам практически все, кроме того, что действительно имеет отношение к проблеме.2.
handleFilesChange
есть в коде, но только в родительском! Это может быть причиной, по которой он не работает3. @thomas, я включил его в onChange. Разве это не срабатывает таким образом?
4. @Iwrestledabearonce. Это все, что у меня есть для обработки изменений файлов. Что еще вы хотели бы увидеть?
5. @penguin это должно быть запущено, я не понимаю, почему этого не должно быть… что происходит, когда вы помещаете журнал консоли внутри
handleFilesChange
функции? Отображается ли он каждый раз, когда вы загружаете новые файлы?
Ответ №1:
РЕДАКТИРОВАТЬ: Если вы хотите console.log
, чтобы он запускался в компоненте uploadFile, вам необходимо запустить повторный запуск. В настоящее время я не вижу, чтобы вы использовали props.files
метод рендеринга внутри компонента uploadFile. Может быть, попробуйте это:
const UploadFile = (props) => {
// stuff here
console.log(props.files);
const randomClassName = `random-class-name-${props.files.length}`;
return {
<Form.Group controlId="formFileMultiple" className="mb-3">
<Form.Label className={randomClassName}> Files </Form.Label>
<Form.Control
type="file" multiple
onChange={props.handleFilesChange}
name="files"
key="files"
/>
</Form.Group>
}
}
Но правильным способом сделать это было бы использовать useEffect
хук, который срабатывает каждый раз, когда ваша переменная изменяется независимо от метода рендеринга. Вот пример:
import { useEffect } from "react";
const UploadFile = (props) => {
useEffect(() => {
// stuff here
console.log(props.files);
}, [props.files]);
return {
<Form.Group controlId="formFileMultiple" className="mb-3">
<Form.Label> Files </Form.Label>
<Form.Control
type="file" multiple
onChange={props.handleFilesChange}
name="files"
key="files"
/>
</Form.Group>
}
}
Комментарии:
1. Просто попробовал это. К сожалению, это не работает. Получил тот же результат, что и раньше.
2. обновил ответ, не уверен, поможет ли это вам, но вы можете попробовать это ^^
3. Привет @thomas. Я не слышал об эффектах использования, поэтому я буду проводить дополнительные исследования по этому вопросу. Спасибо за это! Но я попробовал то, что вы написали, и я все еще получаю исходный результат снова: (
Ответ №2:
React не знает, как управлять FileList
и не видит эти изменения реквизитов в дочернем компоненте. Если вы конвертируете FileList
в array
него, он работает отлично.
const UploadFile = (props) => {
// stuff here
console.log(props.files);
return <ReactBootstrap.Form.Group controlId="formFileMultiple" className="mb-3">
<ReactBootstrap.Form.Label> Files </ReactBootstrap.Form.Label>
<ReactBootstrap.Form.Control
type="file" multiple
onChange={props.handleFilesChange}
name="files"
key="files"
/>
</ReactBootstrap.Form.Group>
}
function App() {
const [listOfFiles, setListOfFiles] = React.useState([]);
const handleFilesChange = (e) => {
setListOfFiles(Array.from(e.target.files));
}
return <UploadFile
handleFilesChange = { e => handleFilesChange(e) }
files = {listOfFiles}
/>
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
<script src="https://unpkg.com/react/umd/react.production.min.js" crossorigin></script>
<script
src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"
crossorigin></script>
<script
src="https://unpkg.com/react-bootstrap@next/dist/react-bootstrap.min.js"
crossorigin></script>
<div id="root"></div>
Уточнение:
Список файлов не управляется react, поскольку его значение может быть установлено только пользователем, а не программно: https://reactjs.org/docs/uncontrolled-components.html#the-file-input-tag
Комментарии:
1. Спасибо. Однако мне нужно сохранить тип как список файлов, потому что это требуется для службы, в которую «файлы» будут вводиться в качестве входных данных. Кажется, что нет способа преобразовать массив обратно в список файлов или есть?
2. Нет @penguin. Вам нужно будет сохранить
FileList
иarray
как реквизит.3. Спасибо за вашу помощь! Оказывается, сервис использует оба типа (список файлов и массив) и работает отлично, поэтому нет необходимости в двух реквизитах. У меня также возник еще один быстрый вопрос — если бы я хотел использовать «files» в качестве входных данных для функции в uploadFile, после того, как пользователь выберет файлы, как бы я это сделал? Я обновил приведенный выше код, чтобы включить функцию (filesFunction) и onChange (добавил второй onChange), но это не работает, так как у нас не может быть двух onChanges одновременно.
4. если я правильно понимаю:
onChange={(e) => {props.handleFilesChange(e); otherFunction(e.target.files) }}
или лучше вhandleFilesChange