React Firebase image url not being saved - reactjs

I want to upload images to FireBase storage and then save the image url to the firebase firestore database. It works 50% of the time but sometimes the url shows up as null.
CODE:
const onUpload = async () => {
setLoading3(true);
for (let i = 0; i < campaignImage.length; i += 1) {
const file = campaignImage[i]
const storageRef = storage.ref()
const fileRef = storageRef.child(file.name)
await fileRef.put(file)
setUrl(await fileRef.getDownloadURL())
db.collection("campaigns").doc(campaignName).update({
images: firebase.firestore.FieldValue.arrayUnion({
name: file.name,
url: url
})
})
}
The file name works perfectly but the url sometimes doesn't show. The image upload is always successful but placing the image url into the firestore collection is not working.

It sounds like setUrl() is a react state hook. When you call it, it will not immediately affect the value of the variable it provides. If you need to use the URL from getDownloadURL(), you should save it to a local variable. The url from the state hook will get its new value after the component renders again.
const downloadUrl = await fileRef.getDownloadURL())
setUrl(downloadUrl)
db.collection("campaigns").doc(campaignName).update({
images: firebase.firestore.FieldValue.arrayUnion({
name: file.name,
url: downloadUrl
})

Related

Uploading multiple content to Cloudinary React js

I'm building this website where users can sometimes upload one audio or one image and sometimes both at the same time to cloudinary. I'm able to upload from the front-end (react.js) one or the other (image or audio) but not both at the same time.
I saw this post that says that it is not possible except if we "write a script and use multi-threads (up to 10 threads) to upload many files at once. " I have no idea what it means in the context of react.js | JavaScript.
My code is the following:
I first call the handleUploadCloudinary with its parameter. The function is being called once the data is ready to be published.
const publishTheEntry = () => {
const {
mainText,
mediaAudio,
mediaImg
} = formData;
if(mediaAudio !== ""){
handleUploadCloudinary("audio");
};
if(mediaImg !== ""){
handleUploadCloudinary("image");
};
};
The handleUploadCloudinary() is the following:
const handleUploadCloudinary = (mediaType) => {
const {
mediaAudio,
mediaImg
} = formData;
const formDataCloudinary = new FormData();
formDataCloudinary.append("upload_preset", my_var_here);
formDataCloudinary.append("timestamp", (Date.now() / 1000) | 0);
if(mediaType === "img"){
formDataCloudinary.append("file", mediaImg);
axios.post(
"https://api.cloudinary.com/v1_1/sismographie-cloud/image/upload",
formDataCloudinary
).then((response) => {
console.log(response);
let url = response.data.secure_url;
setFormData({...formData, mediaImg: url});
})
}else if(mediaType === "audio"){
formDataCloudinary.append("file", mediaAudio);
axios.post(
"https://api.cloudinary.com/v1_1/sismographie-cloud/upload",
formDataCloudinary
).then((response) => {
let url = response.data.secure_url;
setFormData({...formData, mediaAudio: url});
})
}
};
Even if, for when both audio + image are stored into the state, I can console.log() both of the conditions, the state won't bot update the formData with both. One will successfully sate the state with a new cloudinary link while the other one will remain a buffer.
You can loop through your resources list and upload assets one by one, or create new threads at the backend (best practice).
This link is a demo for uploading multiple files using Axios and React:
https://codesandbox.io/s/chunked-client-side-upload-forked-vqx6mp?file=/src/CldCustUploadLgRestApi.js

Firebase Storage: Object does not exist

I have the below code in my ReactJS file that is to upLoad a file to Firebase.
async function uploadFile() {
console.log('starting UPLOAD ========');
const blob = await fetch(mediaBlobUrl).then((r) => r.blob());
const path = '/recordings/one';
firebase
.storage()
.ref(path)
.put(blob)
.then(function (snapshot) {
console.log('Uploaded complete');
});
console.log(`====> setURL is ${setURL} <=======`);
storage.ref(path).getDownloadURL().then(setURL);
}
The first time the button is clicked I get this error, but the the second time I click it then it works. Not sure what is going on?
Firebase Storage: Object 'recordings/one' does not exist. (storage/object-not-found)
I did notice when it fails this is the URL it is trying to hit (404). Notice the %2 instead of "/"
https://firebasestorage.googleapis.com/v0/b/buerce.appspot.com/o/recordings%2Fone 404
That's because your getDownloadURL method runs before actually uploading file. Both the put and getDownloadURL method returns promises. Your function is async so I'd recommend using await for both upload and getDownloadURL methods just like you are doing on fetch method.
async function uploadFile() {
console.log('starting UPLOAD ========');
const blob = await fetch(mediaBlobUrl).then((r) => r.blob());
const path = '/recordings/one';
await firebase.storage().ref(path).put(blob)
const setURL = await storage.ref(path).getDownloadURL()
console.log(`====> setURL is ${setURL} <=======`);
}

How do I trigger a rerender in react?

The idea is that I select an image which then gets uploaded to mongodb and in the same time as I press on upload button I want to trigger rerendering of the page so that the avatar gets updated with the newest image. To accomplish that I first send a PUT request t the server and right after that I set a local storage obejct with the values of the response.
The functions that capture and upload the image
const [reload, setReload] = React.useState(false);
React.useEffect(() => {}, [reload])
const fileSelectedHandler = evt => setAvatarImage(evt.target.files[0]);
const uploadProfileImage = async evt => {
evt.preventDefault();
const formData = new FormData();
formData.append('image', avatarImage);
try {
const response = await axios({
method: 'PUT',
url: `${keys.SERVER_URL}/user/avatar/${isAuthenticated()._id}`,
data: formData,
headers: { 'Content-Type': 'multipart/form-data',}
});
localStorage.setItem(localStorageName, JSON.stringify({ avatar: response.data.user.avatar }));
} catch (error) {
console.log(error);
}
setReload(prevState => !prevState);
}
The thing is that the image is getting uploaded and is displayed correctly. The problem is that after I press on upload button the image is not shown instantly but I have to manually reload the page. Thats why I added that setReload. So that when I press on upload button the value of reload variable gets changed, that triggering a reload in useEffect.
The best practice is to use setState or something similar depending on your state management. localStorage does not trigger rerenders. React isn't designed that way.

Value of state variable is lost - React

I want to build a CRUD in React with Laravel and Firebase. Everything is perfect when I'm working with text, but I got trouble when I try to upload an image to Firebase Storage. I can save it but I can't get its URL.
I wrote 2 "console.log". In the first one the URL is there, but the second one (when I try to get the URL from the state variable) doesn't return anything.
handleSubmit = event =>{
event.preventDefault();
const {imagen} = this.state;
if(imagen!=null){
const uploadTask = storage.ref(`imagenes/${imagen.name}`).put(imagen);
uploadTask.on('state_changed',
(snapshot) => {
const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
this.setState({progress});
},
(error) => {
console.log(error);
},
() => {
storage.ref('imagenes').child(imagen.name).getDownloadURL().then(url => {
this.setState({url});
console.log(this.state.url); //<<<<<<<<<<<<<SHOW URL (IT'S OK!)
})
});
}
var direccion = null;
const form = event.target;
let data = new FormData(form);
data.append('url', this.state.url);
console.log(this.state.url); //<<<<<<<DOESN'T SHOW URL !! (HERE'S THE TROUBLE)
If you want to check the entire file:
https://github.com/AndresVasquezPUCE/project/blob/master/pelicula
I'm not a professional, so please don't be rude :D
this.setState is asynchronous
If you want to get the updated state value, add a callback and access the new state there like
this.setState({ url: 'some url'}, () => {
conosle.log(this.state.url);
});
Data is loaded from Firebase asynchronously. By the time your console.log(this.state.url); //<<<<<<<DOESN'T SHOW URL !! (HERE'S THE TROUBLE) the data hasn't been loaded from Firebase yet, and the then hasn't been called yet.
Any code that needs the data from Firebase needs to either be inside the then() callback (such as console.log(this.state.url); //<<<<<<<<<<<<<SHOW URL (IT'S OK!)) or be called from there (such as this.setState({url})).

React Redux Firebase Upload File Object

Trying to pass the file object to redux action and perform the function inside of an redux action, not sure its the correct way? but basically i want back downloadURL from firebase upload complete so I can show image front end.
createLocation(event) {
event.preventDefault();
const fileObject = this.state.file;
const test = {
fileObject
}
this.props.uploadImage_func(test);
}
and action function:
export function uploadImage_func(fileObject) {
return dispatch => {
const fileName = 'myimage';
const storageRef = firebase.storage().ref('test/' + fileName);
const task = storageRef.put(fileObject);
task.on('state_changed',
function complete(snapshot) {
const downloadURL = task.snapshot.downloadURL;
},
).then(function () {
dispatch(attemptLogin({
...downloadURL
}));
});
}
}
error:
As you can see you have got an error Invalid argument in 'put' at index 0: Expected Blob or File. So first of all you need path exactly File or Blob. If you did right in you createLocation and got file object than you need not to wrap it in const test object more. That action causes unnecessary nesting, so just path fileObject as it is. And more. When you subscribe for firebase UploadTask on event you need to path callback functions and do it in a right order, so try to use next:
uploadTask.on('state_changed',
(snapshot) => {
// here you could log loading information in percents but uploading is not finished yes
console.log((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
},
(error) => console.log(error),
() => {
// And after uploading is complete you could get your download url
console.log('Call save img', uploadTask.snapshot.downloadURL);
}
);
For more information read documentation for Firebase Storage (Upload files)

Resources