我正在使用 React 和 Firebase。我正在嘗試將影像的下載 url 存盤到名為“image”的狀態,然后使用該狀態添加到正在創建的帖子中的“imageurl”欄位。更新影像狀態似乎沒有問題,但是當我查看在我的 firebase 資料庫中創建的新帖子物件中的“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;
uj5u.com熱心網友回復:
您應該使用狀態來觸發對 UI 的更新,并使用其他同步原語來確定何時更新資料庫。
例如,在最簡單的情況下,您可以createPost在獲得下載 URL 時從嵌套偵聽器中呼叫:
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
};
uj5u.com熱心網友回復:
上傳檔案需要一段時間。所以最好在上傳完成后呼叫創建帖子。
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;
uj5u.com熱心網友回復:
或者,只需在您的代碼中更改一件事,它也可以正常作業,因為上傳功能具有createpost您在完成上傳時呼叫的異步操作并將下載 url 傳遞給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;
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/419534.html
標籤:
