Question: When props.files
is console logged (look at code below to see where it's logged), it works the first time. But, when I select a new set of files, it never console logs anything again, unless I reload the page and start over. What am I doing wrong here?
Info on my code:
I am using React Bootstrap Form Components (scroll to "File Input") for the following custom component (i.e. Form.Group, Form.Label, Form.Control). Code is heavily simplified for clarity:
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>
}
In the parent, I have an instance of the custom UploadFile component, as such:
const [listOfFiles, setListOfFiles] = useState([]);
const handleFilesChange = (e) {
setListOfFiles(e.target.files);
}
<UploadFile
handleFilesChange = { e => handleFilesChange(e) }
files = {listOfFiles}
/>
CodePudding user response:
EDIT: If you want to console.log
to be triggered in the UploadFile component, you have to trigger a rerender. Currently I don't see you using props.files
inside the render method of the UploadFile component. Maybe try this:
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>
}
}
But the proper way of doing this would be using the useEffect
hook, which gets triggered every time your variable changes independently of the render method. Here's an example:
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>
}
}
CodePudding user response:
React doesn't know how to manage the FileList
and doesn't see these props changes in the child component. If you convert FileList
to array
it works perfectly.
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>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
Clarification:
The FileList is unmanaged by react, because its value can only be set by a user and not programmatically: https://reactjs.org/docs/uncontrolled-components.html#the-file-input-tag