我的 firebase 存储中的下载 URL 没有传输到数据库
My download URL in my firebase storage is not transferring to the database
我正在使用 React 和 Firebase。我正在尝试将图像的下载 url 存储到名为 'image' 的状态,然后使用该状态添加到正在创建的 post 中的 '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 and/or 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
};
文件上传需要一些时间。所以最好在上传完成后调用create post。
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;
或者只需更改代码中的一件事,它也可以正常工作,因为上传功能具有异步操作,您在完成上传后调用 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;
我正在使用 React 和 Firebase。我正在尝试将图像的下载 url 存储到名为 'image' 的状态,然后使用该状态添加到正在创建的 post 中的 '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 and/or 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
};
文件上传需要一些时间。所以最好在上传完成后调用create post。
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;
或者只需更改代码中的一件事,它也可以正常工作,因为上传功能具有异步操作,您在完成上传后调用 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;