Reputation:
I am a newcomer to React development. The function I currently want to achieve is to allow users to send uploaded pictures. This function is similar to messenger uploading pictures and can be sent together with text. The following is my current code:
import React, { useState } from 'react'
import "./ChatInput.css"
import { useStateValue } from './StateProvider';
import db from './firebase';
import firebase from 'firebase';
import { storage } from './firebase';
function ChatInput({channelName, channelId}) {
const [input, setInput] = useState("");
const [{user}] = useStateValue();
const [image, setImage] = useState(null);
const [imageUrl, setImageUrl] = useState("");
const sendMessage = (e) => {
e.preventDefault();
if(channelId){
db.collection('courses').doc(channelId).collection('messages').add({
message:input,
timestamp:firebase.firestore.FieldValue.serverTimestamp(),
user:user.displayName,
userImage: user.photoURL,
});
}
setInput("");
};
const fileSelectedHandler = e => {
if (e.target.files[0]) {
setImage(e.target.files[0]);
}
};
const fileUploadedHandler = () => {
const uploadTask = storage.ref(`images/${image.name}`).put(image);
uploadTask.on(
"state_changed",
snapshot => {},
error => {
console.log(error);
},
() => {
storage
.ref("images")
.child(image.name)
.getDownloadURL()
.then(url => {
setImageUrl(url)
});
}
);
}
return (
<div className ="chatInput">
<form>
<input
value ={input}
onChange={(e)=>setInput(e.target.value)}
placeholder={`Message #${channelName?.toLowerCase()}`} />
<button type="submit" onClick={sendMessage}>SEND</button>
</form>
<input type="file" onChange={fileSelectedHandler}/>
<button type="submit" onClick={fileUploadedHandler}>UPLOAD</button>
<br />
<img src={imageUrl} alt="" />
</div>
);
}
export default ChatInput;
Because the picture is stored in firebase-storage, and the message sent by the user is stored in firestore. I don't know how to connect the two of them. I hope someone can provide answers and suggestions on the code will be better.
Upvotes: 2
Views: 1541
Reputation: 1283
const [messages, setMessages] = useState([]);
useEffect(()=>{
db
.collection('courses')
.doc(channelId)
.collection('messages')
.orderBy("timestamp","desc")
.onSnapshot((snapshot)=>
setMessages(
snapshot.docs.map((doc)=>({
id: doc.id,
data: doc.data()
}))
)
)
},[]);
return(
{
messages.map(({id,data:{content,user,timestamp,userImage}})=>(
<Message
message={content}
user={user}
id={id}
key={id}
createdAt={timestamp}
senderImgSrc={userImage}
/>
))
}
)
As your storing the imageUrl
in firestore you don't have to look up to your storage anymore as the url is going to remain the same. That's why I am using the url that is stored in the firestore.
You can create your own message component.
Upvotes: 1
Reputation: 317497
Typically you store the path of the file in storage, or download URL (or both), as fields in the related document. This typically assumes that you upload to storage first, then write the document. But you could always update the document after the upload completes.
Some people also use the same randomly generated ID of the document as the name of the file in storage, so you always know how to get from one to other.
Upvotes: 1