Home > Software engineering >  Key={id} not working in react while mapping
Key={id} not working in react while mapping

Time:12-08

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.

  • Related