I am making a simple messaging app, when i try to send messages the same div gets updated with new message but a new div does not get added. i was using index first while mapping the messages to display but it did not work so i added a msgId to the messages and tried to use it as the key but it's still not working this is OpenConversation.js
import React, { useState } from 'react'
import {Button, Form, InputGroup, ListGroup} from 'react-bootstrap'
import { useConversations } from '../contexts/ConversationsProvider'
export default function OpenConversation() {
const[text,setText]=useState()
const {sendMessage,selectedConversation}=useConversations()
function handleSubmit(e) {
e.preventDefault()
console.log("index",selectedConversation)
sendMessage(
selectedConversation.recipients.map(r => r.id),
text
)
setText('')
}
return (
<div className="d-flex flex-column flex-grow-1">
<div className="flex-grow-1 overflow-auto">
<div className="d-flex flex-column align-items-start justify-content-end px-3">
{selectedConversation.messages.map((message) => {
return (
<div
key={message.msgId}
className={`my-1 d-flex flex-column ${message.fromMe ? 'align-self-end align-items-end' : 'align-items-start'}`}
>
<div
className={`rounded px-2 py-1 ${message.fromMe ? 'bg-primary text-white' : 'border'}`}>
{message.text} {message.msgId}
</div>
<div className={`text-muted small ${message.fromMe ? 'text-right' : ''}`}>
{message.fromMe ? 'You' : message.senderName}
</div>
</div>
)
})}
</div>
</div>
<Form style={{position:'absolute',bottom:'0rem'}}
onSubmit={handleSubmit}
>
<Form.Group className='m-2'>
<InputGroup >
<Form.Control as='textarea' required
value={text}
onChange={e=>setText(e.target.value)}
style={{height:'75PX',resize:'none',}}
/>
<Button type="submit" style={{background:'#7c73e6',border:'none'}}>Send</Button>
</InputGroup>
</Form.Group>
</Form>
</div>
)
}
ConversationsProvider.js
import React, { useContext, useState, useEffect, useCallback } from 'react'
import useLocalStorage from '../hooks/useLocalStorage';
import { useContacts } from './ContactsProvider';
import {v4 as uuidv4} from 'uuid'
const ConversationsContext = React.createContext()
export function useConversations() {
return useContext(ConversationsContext)
}
export default function ConversationsProvider({ id, children }) {
const [conversations, setConversations] = useLocalStorage('conversations', [])
const [selectedConversationIndex,setSelectedConversationIndex]=useState(0)
const { contacts } = useContacts()
function createConversation(recipients) {
setConversations(prevConversations => {
return [...prevConversations, { recipients, messages: [] }]
})
}
function selectConversationIndex(i)
{
setSelectedConversationIndex(i)
}
function addMessageToConversation({recipients,text,sender})
{
setConversations(prevConversations=>{
let madeChange=false
let msgId=uuidv4()
const newMessage={sender,text,msgId}
const newConversations=prevConversations.map(conversation=>{
if(arrayEquality(conversation.recipients,recipients))
{
madeChange=true
return{
...conversation,
messages:[conversation.messages,newMessage]
}
}
return conversation
})
if(madeChange){
return newConversations
}
else{
return [...prevConversations,{recipients,messages:[newMessage]}]
}
})
console.log(conversations)
}
function sendMessage(recipients,text)
{ console.log("working")
addMessageToConversation({recipients,text,sender:id})
}
const formattedConversations = conversations.map((conversation, index) => {
const recipients = conversation.recipients.map(recipient => {
const contact = contacts.find(contact => {
return contact.id === recipient
})
const name = (contact && contact.name) || recipient
return { id: recipient, name }
})
const messages = conversation.messages.map(message => {
const contact = contacts.find(contact => {
return contact.id === message.sender
})
const name = (contact && contact.name) || message.sender
const fromMe = id === message.sender
return { ...message, senderName: name, fromMe }
})
const selected = index === selectedConversationIndex
return { ...conversation, messages, recipients, selected }
})
const value = {
conversations: formattedConversations,
selectedConversation: formattedConversations[selectedConversationIndex],
sendMessage,
selectConversationIndex: setSelectedConversationIndex,
createConversation
}
return (
<ConversationsContext.Provider value={value}>
{children}
</ConversationsContext.Provider>
)
}
function arrayEquality(a, b) {
console.log("working")
if (a.length !== b.length) return false
a.sort()
b.sort()
return a.every((element, index) => {
return element === b[index]
})
}
i did not understand why index did not work, is there another way to map the messages?
CodePudding user response:
Your error comes from this line
messages:[conversation.messages,newMessage]
in the addMessageToConversation
function
I think you need to spread conversation.messages.
Change [conversation.messages, newMessage]
to [...conversation.messages, newMessage]
.
With what you're doing currently, you're making the previous messages object, the first item in the array and then the new one as the second item.