reactjstypescriptpromise

How to map an array from a promise


I am not well versed with promises and cannot find how to retrieve properties from it. I inherited the following code:

   const [MessageData, setMessageData] = useState<any | null>(null);         
   const [snackbarData, setSnackbarData] = useState<any | null>(null);        
   PCore.getFeedUtils().getFeeds(feedKey, 'pyDashboardFeed', className, [], [],     thePConn,   false)       
       .then(() => {         
            setMessageData({           
                messageList: thePConn.getValue("pulse.messages","") || {},            
                messageIDs: (thePConn.getValue("pulse.messageIDs","")as any) || [],       
            });     
        })       
        .catch(() => {         
             setSnackbarData({ show:true, message:"Error retrieving comments"});     
        });

I need to get the properties in messageList, but I'm not sure how to do that.

If i stringify messageData, I get the following:

{"messageList": {       
   "SOCIAL M-369": {         
      "pxUpdateDateTime":"2025-01-13T19:50:39.417Z",         
      "pxCreateDateTime":"2025-01-13T19:50:39.417Z",         
      "postedByUser":{           
         "name":"Paul Smith",           
         "ID":"psmith@email.com"           
      },         
      "pyMessage":"test comment 2",         
      "ID":"SOCIAL M-369"       
   },        
   "SOCIAL M-368":{          
      "pxUpdateDateTime":"2025-01-13T19:45:29.091Z",          
      "pxCreateDateTime":"2025-01-13T19:45:29.091Z",          
      "postedByUser":{            
         "name":"Paul Smith",            
         "ID":"psmith@email.com"           
      },          
      "pyMessage":"test comment",          
      "ID":"SOCIAL M-368"        
   }      
},      
"messageIDs":["SOCIAL M-369","SOCIAL M-368"]} 

But I cannot determine how to display the list of properties within messageList. I tried

const messageDetail = MessageData.map(messageList => (         
   <li key={messageList.ID}>           
      <div>{messageList.pyMessage}</div>         
   </li>       
))

but get the error 'Cannot read properties of null (reading 'map')'. Any ideas how to properly define the list?


Solution

  • Problem

    The issue arises because MessageData starts as null, and when you try to use map directly on it, it throws an error. (Since map is a method on Array.)

    There are different approaches you could take, but I would personally do something like this:

    Approach 1:

    const [MessageData, setMessageData] = useState<any | null>(null); 
    
    const messageDetail = MessageData?.messageIDs?.map(messageId=> (         
       <li key={messageId}>           
          <div>{MessageData?.messageList?.[messageId]?.pyMessage}</div>         
       </li>       
    ))
    

    Using Optional chaining (?.) ensures the code doesn't break when it can't access a property. Docs

    This way you are mapping over the array messageIDs that only contains the ids, then you use the messageID as an index to get the full data that's stored in messageList.

    Approach 2:

    You are storing 2 properties in MessageData, messageList and messageIDs. Since messageList is an Object instead of an Array you have to transform it before you can map over it. (Using Object.values)

    const messageDetail = MessageData?.messageList 
      ? Object.values(MessageData.messageList).map(message => (
          <li key={message.ID}>
            <div>{message.pyMessage}</div>
          </li>
        ))
      : null; // Handle the case where MessageData or messageList is null
    
    Sidenote

    the convention for useState, and most variable names in general, in JS/TS is to use camelCase. So MessageData would be messageData.

    Whenever you see something that starts with a capital letter, you can in most cases assume it's either a Class or a Type/Interface if conventions were followed.