In react
const allInputs = { imgUrl: '' };
const [imageAsFile, setImageAsFile] = useState('');
const [imageAsUrl, setImageAsUrl] = useState(allInputs);
const [media, setMedia] = useState(null);
const handleImageAsFile = (e) => {
const image = e.target.files[0]
setImageAsFile(imageFile => (image));
console.log(imageAsFile);
}
Here is the input code, when I click this button, all types of files show, but I want to be able to store the type of file it is in a variable
<input type="text"
id="phone"
onChange={(e) => setPhone(e.target.value)}
/>
For example, if I select an image, how can know the type of image I have selected? If it is png or jpg or whatever before uploading it to the database.
First, React Javascript works the exact way Javascript works everywhere, For accessing the image type refer to the below code, I have added the comments for better understanding.
const [imageAsFile, setImageAsFile] = useState('');
const [imageAsUrl, setImageAsUrl] = useState(allInputs);
const [media, setMedia] = useState(null);
const handleImageAsFile = (e) => {
//image var holds the file object which has a type property
const image = e.target.files[0];
console.log(image.type); // this will output the mime, i.e "image/png" or "image/jpg"
setImageAsFile(imageFile => (image));
console.log(imageAsFile);
}
Related
This question already has answers here:
The useState set method is not reflecting a change immediately
(15 answers)
Closed last month.
I'm new to react and I'm trying to make an app, where user can upload multiple images at once, and those images get sent to the firebase storage, and urls of those images get stored in an array inside a doc, so that later on they can be accessed in a different page.
Here is a snippet of my code:
function CreateCarParts({isAuth}) {
const [images, setImages] = useState(null);
const [imageUrls, setImageUrls] = useState([]);
let navigate = useNavigate();
const postsCollectionRef = collection(db, "CarParts")
useEffect(() => {
if (!localStorage.getItem('isAuth')){
navigate("/login");
};
}, []);
const uploadImages = async () => {
if(images === null) return;
let uniqueFolderName = new Date().getTime().toString();
const imageList = Array.from(images);
for(let i = 0; i < imageList.length; i++) {
const image = imageList[i];
const imageLinkName = `carParts/${uniqueFolderName}/${image.name}`;
const imageRef = ref(storage, imageLinkName);
const snapshot = await uploadBytes(imageRef, image);
const url = await getDownloadURL(snapshot.ref);
setImageUrls((prev) => [...prev, url]);
}
alert("Images Uploaded");
};
const createPost = async () => {
await uploadImages();
await addDoc(postsCollectionRef, {imageUrls});
navigate('/carparts');
};
return (
<>
<Form.Control onChange={(event) => {setImages(event.target.files);uploadImages();}} type="file" multiple />
<Button onClick={createPost}> Submit </Button>
</>
)
}
export default CreateCarParts;
The images get sent to the storage, and the doc is created successfully, however the imageUrls array is empty. I can't figure out why it's not working, I assume I'm using the useState() incorrectly.
imageUrls won't be updated in the same render cycle, so calling await addDoc(postsCollectionRef, {imageUrls}); right after await uploadImages(); won't work
I would store urls in a local array instead
function CreateCarParts({isAuth}) {
const [images, setImages] = useState(null);
let navigate = useNavigate();
const postsCollectionRef = collection(db, "CarParts")
useEffect(() => {
if (!localStorage.getItem('isAuth')){
navigate("/login");
};
}, []);
const uploadImages = async () => {
if(images === null) return;
let uniqueFolderName = new Date().getTime().toString();
const imageList = Array.from(images);
const urls = [];
for(let i = 0; i < imageList.length; i++) {
const image = imageList[i];
const imageLinkName = `carParts/${uniqueFolderName}/${image.name}`;
const imageRef = ref(storage, imageLinkName);
const snapshot = await uploadBytes(imageRef, image);
const url = await getDownloadURL(snapshot.ref);
urls.push(url);
}
alert("Images Uploaded");
return urls;
};
const createPost = async () => {
const imageUrls = await uploadImages();
await addDoc(postsCollectionRef, {imageUrls});
navigate('/carparts');
};
return (
<>
<Form.Control onChange={(event) => {setImages(event.target.files);uploadImages();}} type="file" multiple />
<Button onClick={createPost}> Submit </Button>
</>
)
}
export default CreateCarParts;
I am currently facing a rather strange issue and was wondering if anyone would know the solution. I am making an api call to my Django backend to get details on profiles
export const ProfilesPage = () => {
const classes = useStyles()
useEffect(() => {
getProfiles()
})
const [profiles, setProfiles] = useState([])
let imgLink = ''
let getProfiles = async () => {
let response = await fetch('http://127.0.0.1:8000/api/profiles', {
method: "GET"
})
let data = await response.json()
// console.log(data[0].profile_image)
imgLink = 'http://127.0.0.1:8000' + data[0].profile_image
console.log(imgLink)
}
return (
<div className={classes.root}>
ProfilesPage
<img alt='profile' src={imgLink} />
</div>
)
}
the last line of my getProfiles function I am console.loging the image link. The link is appearing on my console and when i click on it, the correct image is being opened in my browser. I am unsure why react is not displaying the image when the link is clearly working. Thank you,
Try using state instead of let img = ''
Example:
const [img, setImg] = useState([]);
useEffect(() => {
const getProfiles = async () => {
let response = await fetch('http://127.0.0.1:8000/api/profiles', {
method: "GET"
})
let data = await response.json()
// console.log(data[0].profile_image)
imgLink = 'http://127.0.0.1:8000' + data[0].profile_image
setImg(imgLink)
}
getProfiles();
}, [profiles])
Then use the state in your return:
return (
<div className={classes.root}>
ProfilesPage
<img alt='profile' src={img} />
</div>
)
Because you are trying to store the image URL in imgLink it's being reset to empty string each time the component is re-rendered.
What you can try is storing the image URL in a state which will persist between each render.
i want to add data after uploading 1 image
const [file, setFile] = useState(null);
const handleUpload = (e) => {
setFile(e.target.files);
};
<input
type="file"
onChange={(e) => handleUpload(e)}
ref={fileInputRef}
multiple
/>
this was work if i select 2 or more files at once.
however i want to handle after choosing 1 image. user will be upload using the same input.
i have tried using method below and created error TypeError: file is not iterable
const handleUpload = (e) => {
setFile([...files, e.target.files]);
};
or
const handleUpload = (e) => {
let filesArray = file;
if (file) {
for (var i = 0; i < file.length; i++) {
filesArray.push(e.target.files[i]);
}
}
setFile(filesArray);
};
do you guys have any solution?
You should first set the default value for file as an array in your useState, then while using the set method you need to use the spread (...) operator properly. This will resolve your error TypeError: file is not iterable
Below are the changes that you will need to perform.
export default function InputComponent() {
const [file, setFile] = React.useState([]);
const handleUpload = (e) => {
setFile([...file, ...e.target.files]);
};
return (
<div>
<input type="file" onChange={(e) => handleUpload(e)} multiple /><br/><br/>
<textarea value={file}/>
</div>
);
}
So I am working on my React app and a one point i need to upload some files. So I simply used the input file to make it work. I set its display none as I wanted my attachment icon to be clicked when wanting to upload the file.
Problem : Using the ref method, everything is working fine except one thing and that is below in my hangleFileChange function, when the setFiles() set the file variable, the component is not rendered and I do not see the file array. but if I do the file saving simply like
setFile(event.target.files[0])
I can see the rendering . But with the below code, the component is not rendering
import React, { useRef, useState } from "react";
const App = () => {
const fileInput = useRef(null);
const [file, setFile] = useState([]);
const handleClick = () => {
fileInput.current.click();
};
const handleFileChange = (event) => {
console.log("Make something");
let newFiles = file;
newFiles.push(event.target.files[0]);
console.log(newFiles);
setFile(newFiles);
};
// This should run on every render
console.log("the files array is ", file);
return (
<div className="patientactions-container">
<input
type="file"
style={{ display: "none" }}
onChange={(e) => handleFileChange(e)}
ref={fileInput}
/>
<div onClick={() => handleClick()}>clck</div>
</div>
);
};
export default App;
Please help.
Sandbox : https://codesandbox.io/s/kind-breeze-czc3w?file=/src/App.js:0-692
Try this version
const handleFileChange = (event) => {
console.log("Make something");
// Set the ne variable to an array, not file
let ne = [];
ne.push(event.target.files[0]);
// then set it equals file.
ne = file;
console.log(ne);
console.log(file);
setFile(file);
};
You can fix the code like this below.
import React, { useRef, useState } from "react";
const App = () => {
const fileInput = useRef(null);
const [file, setFile] = useState(null);
const handleClick = () => {
fileInput.current.click();
};
const handleFileChange = (nfile) => {
console.log("Make something");
if (file == null) setFile([nfile]);
else setFile([...file, nfile]);
};
console.log("the files array", file);
return (
<div className="patientactions-container">
<input
type="file"
style={{ display: "none" }}
onChange={(e) => handleFileChange(e.target.files[0])}
ref={fileInput}
/>
<div onClick={() => handleClick()}>clck</div>
</div>
);
};
export default App;
I'd have put this in the comments but my rep is not high enough.
I had a problem with rendering changes to an array, because arrays use pointers it did not "register" a state change that was enough to cause a render. Using the spread operator in your solution affected the pointer and thus a render occurred.
In my own solution I set my array to null before adding content and that worked fine for my problem.
I'm trying to upload a picture using react hooks
const [picture, setPicture] = useState();
const onChangePicture = e => {
console.log('picture: ', picture);
setPicture(...picture, e.target.files[0]);
};
<input
type="file"
//style={{ display: 'none' }}
onChange={e => onChangePicture(e)}
/>
however I'm getting the following error:
Uncaught TypeError: picture is not iterable
when I change the onChangePicture to
setPicture(picture, e.target.files[0])
the picture variable is undefined,
any help would be appreciated.
I think you meant to do:
setPicture([...picture, e.target.files[0]]);
This will concatenate the first file to all current files.
Remember to use const [picture, setPicture] = useState([]); as to make sure it doesn't break the first time around
For anybody arriving here looking for how to do it with TypeScript:
const [file, setFile] = useState<File>();
const onChange = (event: React.FormEvent) => {
const files = (event.target as HTMLInputElement).files
if (files && files.length > 0) {
setFile(files[0])
}
}
You can pass the value directly into setPicture function to set the state variable picture.
Try:
const [picture, setPicture] = useState(null);
const onChangePicture = e => {
console.log('picture: ', picture);
setPicture(e.target.files[0]);
};
<input
type="file"
//style={{ display: 'none' }}
onChange={onChangePicture}
/>
onChange = {(e) => this.onChangePicture(e)} can only be written when you made the states as
states = {
image,
name
}
but when using useState()
you need to use
const [image, setImage] = useState("");
onChange = {(e) => setImage(e.target.files[0])}
I hope this solves the error.
I finally fix this issue:
Problem is here
const [picture, setPicture] = useState(null); //Incorrect
You can use this
const [picture, setPicture] = React.useState(""); //Correct
This can fix this issue