我的firebase存储中的下载URL没有传输到数据库



我正在使用React和Firebase。我试图将图像的下载url存储到一个名为"image"的状态,然后使用该状态添加到正在创建的帖子中的"imageurl"字段中。更新图像的状态似乎没有问题,但当我查看firebase数据库中创建的新post对象中的"imageurl"字段时,它是空的。这是代码:

import { storage, db } from '../firebase-config';
import { useState } from 'react';
import { ref, getDownloadURL, uploadBytesResumable } from "firebase/storage";
import { collection, addDoc } from 'firebase/firestore';
import { format } from 'date-fns';
const CreatePost = () => {
const [caption, setCaption] = useState('');
const [progress, setProgress] = useState(0);
const [image, setImage] = useState('');
const postsCollectionRef = collection(db, 'Posts');
const formHandler = (e) => {
e.preventDefault();
const file = e.target[0].files[0];
uploadFiles(file);
createPost();
};

const uploadFiles = (file) => {
if (!file) return;
const storageRef = ref(storage, `files/${file.name}`);
const uploadTask = uploadBytesResumable(storageRef, file);

uploadTask.on(
"state_changed",
(snapshot) => {
const prog = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
setProgress(prog);
},
(error) => console.log(error),

() => {
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
setImage(downloadURL);
});
}
);
};
const createPost = async () => {
const datetime = format(new Date(), 'MMMM dd, yyyy');
const post = await addDoc(postsCollectionRef, {
caption: caption,
imageurl: image,
date: datetime
})
setCaption('');
}

return (
<div>
<form onSubmit={formHandler}>
<input type="file" className="input" />
<button type="submit">Upload</button>
<input value={caption} type='text' placeholder='caption' onChange={(e) => setCaption(e.target.value)} />
</form>
<hr />
<h2>Uploading done {progress}%</h2>
<img src={image} />
<p>{image}</p>
</div>
);    
}
export default CreatePost;

您应该使用状态来触发对UI的更新,并使用其他同步原语来确定何时更新数据库。


例如,最简单的方法是,当您获得下载URL:时,可以从嵌套侦听器中调用createPost

const formHandler = (e) => {
e.preventDefault();
const file = e.target[0].files[0];
uploadFiles(file);
// createPost(); // 👈 don't call this here
};
const uploadFiles = (file) => {
if (!file) return;
const storageRef = ref(storage, `files/${file.name}`);
const uploadTask = uploadBytesResumable(storageRef, file);
uploadTask.on(
"state_changed",
(snapshot) => {
const prog = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
setProgress(prog);
},
(error) => console.log(error),
() => {
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
setImage(downloadURL);
createPost(); // 👈 but instead call it here
});
}
);
};

您可能需要将downloadURL和其他要写入数据的值传递到createPost调用中,这是不使用React的状态来管理数据库更新的另一种情况。


或者,您可以使用Promises和/或async/await来同步调用。

const formHandler = (e) => {
e.preventDefault();
const file = e.target[0].files[0];
const url = await uploadFiles(file); // 👈 wait for upload to be done
createPost(url); // 👈 only then create the post with the url
};
// 👇 this function is asynchronous, meaning it returns a promise
const uploadFiles = (file) => async {
if (!file) return;
const storageRef = ref(storage, `files/${file.name}`);
const uploadTask = uploadBytesResumable(storageRef, file);
uploadTask.on(
"state_changed",
(snapshot) => {
const prog = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
setProgress(prog);
},
(error) => console.log(error)
);
await uploadTask; // 👈 uploadTask is a promise itself, so you can await it

let downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
// 👆 getDownloadURL returns a promise too, so... yay more await
return downloadURL; // 👈 return the URL to the caller
};

上传文件需要一段时间。所以上传完成后最好调用createpost

import { storage, db } from '../firebase-config';
import { useState } from 'react';
import { ref, getDownloadURL, uploadBytesResumable } from "firebase/storage";
import { collection, addDoc } from 'firebase/firestore';
import { format } from 'date-fns';
const CreatePost = () => {

const [caption, setCaption] = useState('');
const [progress, setProgress] = useState(0);
// const [image, setImage] = useState('');  if still need the state for some reason 

const postsCollectionRef = collection(db, 'Posts');

const formHandler = (e) => {
e.preventDefault();
const file = e.target[0].files[0];
uploadFiles(file);
};

const uploadFiles = (file) => {
if (!file) return;
const storageRef = ref(storage, `files/${file.name}`);
const uploadTask = uploadBytesResumable(storageRef, file);

uploadTask.on(
"state_changed",
(snapshot) => {
const prog = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
setProgress(prog);
},
(error) => console.log(error),

() => {
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => { createPost(downloadURL);
});
}
);
};

const createPost = async (imageUrl) => {
// setImage(imageURL); if still need the state for some reason 
const datetime = format(new Date(), 'MMMM dd, yyyy');
const post = await addDoc(postsCollectionRef, {
caption: caption,
imageurl: imageUrl,
date: datetime
})
setCaption('');
}

return (
<div>
<form onSubmit={formHandler}>
<input type="file" className="input" />
<button type="submit">Upload</button>
<input value={caption} type='text' placeholder='caption' onChange={(e) => setCaption(e.target.value)} />
</form>
<hr />
<h2>Uploading done {progress}%</h2>
<img src={image} />
<p>{image}</p>
</div>
);    
}
export default CreatePost;

或者,只需更改代码中的一件事,它也会正常工作,因为上传函数有异步操作,当你完成上传并将下载url传递给createPost时,你可以调用createpost

import { storage, db } from '../firebase-config';
import { useState } from 'react';
import { ref, getDownloadURL, uploadBytesResumable } from "firebase/storage";
import { collection, addDoc } from 'firebase/firestore';
import { format } from 'date-fns';
const CreatePost = () => {

const [image, setImage] = useState('');
const [caption, setCaption] = useState('');
const [progress, setProgress] = useState(0);
const postsCollectionRef = collection(db, 'Posts');
const formHandler = (e) => {
e.preventDefault();
const file = e.target[0].files[0];
uploadFiles(file);
};

const uploadFiles = (file) => {
if (!file) return;
const storageRef = ref(storage, `files/${file.name}`);
const uploadTask = uploadBytesResumable(storageRef, file);

uploadTask.on(
"state_changed",
(snapshot) => {
const prog = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
setProgress(prog);
},
(error) => console.log(error),

() => {
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
setImage(downloadURL)
createPost(downloadURL)
});
}
);
};
const createPost = async (url) => {
const datetime = format(new Date(), 'MMMM dd, yyyy');
const post = await addDoc(postsCollectionRef, {
caption: caption,
imageurl: url,
date: datetime
})
setCaption('');
}

return (
<div>
<form onSubmit={formHandler}>
<input type="file" className="input" />
<button type="submit">Upload</button>
<input value={caption} type='text' placeholder='caption' onChange={(e) => setCaption(e.target.value)} />
</form>
<hr />
<h2>Uploading done {progress}%</h2>
<img src={image} />
<p>{image}</p>
</div>
);    
}
export default CreatePost;

最新更新