chat-ui-kit-react
chat-ui-kit-react copied to clipboard
Exception occurs inside <MessageList> when loop using map
Hi Devs, I am trying to loop through the components there is an exception which occurs when i try to wrap <MessageSeparator/> and <Message/> elements inside <></> it means MessageList doesn't handle empty elements or divs.
const exampleObject = {"2023-03-06":["a","b","c"]};
<MessageList>
{
Object.keys(exampleObject).map(
(timestampKey) => (
<> // here is the problem
<MessageSeparator content={timestampKey} key={uuid()} />
{exampleObject[timestampKey].map((values) => (
<Message
key={uuid()}
model={{
message: values.message,
sentTime: values.sentTime,
sender: values.sender,
direction: values.direction,
position: values.position,
}}
>
<Avatar src={avatarIco} name={values.sender} />
</Message>
))
}
</>
)
)
}
</MessageList>
@saqygee This isn't a Chatscope issue. You're using array maps with React elements incorrectly. You need to use React.Fragment and add a unique key attribute.
https://reactjs.org/docs/fragments.html#keyed-fragments
I already tried that you get this exception :
react_devtools_backend.js:2655 Warning: Failed prop type: "undefined" is not a valid child for ForwardRef(MessageListFunc). Allowed types: Message, MessageGroup, MessageSeparator, MessageListContent
It says undefined because it expects tags one of those allowed types
Right. That's because it says in the docs the only allowed components inside a MessageList are one of those components, so it's by design. I agree that it should be able to accept Fragments though.
One workaround is to make an array of your elements using reduce and then put the array directly into the MessageList. I haven't tested it, but something like this:
const elementArray = Object.keys(exampleObject).reduce((accumulator, timestampKey) => (
accumulator.concat([
<MessageSeparator content={timestampKey} key={uuid()} />,
<MessageGroup key={uuid()}>
<Avatar src={avatarIco} name={values.sender} />
<MessageGroup.Messages>
{exampleObject[timestampKey].map((values) => (
<Message
key={uuid()}
model={{
message: values.message,
sentTime: values.sentTime,
sender: values.sender,
direction: values.direction,
}}
/>
))}
</MessageGroup.Messages>
</MessageGroup>
])
), [])
Then setup your MessageList like this:
<MessageList>
{elementArray}
</MessageList>
Using a forEach would work as well I'm sure.
Is there any other workaround ?
Maybe a better alternative is to return an array inside of the .map
.
<MessageList>
{
Object.keys(exampleObject).map(
(timestampKey) => [
<MessageSeparator content={timestampKey} key={uuid()} />,
exampleObject[timestampKey].map((values) => (
<Message
...
>
... </Message>
))
</>
)
)
}
</MessageList>
@saqygee This isn't a Chatscope issue. You're using array maps with React elements incorrectly. You need to use React.Fragment and add a unique key attribute.
https://reactjs.org/docs/fragments.html#keyed-fragments
Just to avoid confusions the empty tag is a React.Fragment, see https://react.dev/reference/react/Fragment
This is a chatscope issue as an error is thrown if React.Fragment is used. But, for reference, you can add other elements like Box to MessageList and while it will throw that error it will render them (although not 100% sure that the scrolling is perfect, but for debugging information it works), so the restriction on child nodes should be explained better (what types of nodes are allowed as children, in what conditions and what will not work if not using only the recommended children)
Edit: clarified that some other elements can be rendered, irrespective of the error.
It's pretty clear in the docs the allowed child components are:
<Message />
<MessageGroup />
<MessageSeparator />
<MessageListContent />
And what does it mean "not allowed"? If I put a Box it will be rendered. By reading the docs I assumed it will NOT be rendered (or that everything will break), but I did not clean up older code and to my surprise the Box got rendered and it is perfectly fine for my use case (which again, was to show some additional information in admin mode, nothing I could not do otherwise, but much easier if it just works).
Sure, the library can make another release and "ban/block" this behavior, but it would be nicer to just explain "using other elements than these list will result in X".