Salam. I have a simple chat app (Not using socket) that triggers useEffect to map all data from "chats" list (which is an array of objects) as MessageItem or AttachmentItem component to an array called "chatItems". Here is the code:
const [chats, setChats] = useState(list);
const [chatItems, setChatItems] = useState();
useEffect(() => {
setChatItems(
chats.map((item) =>
item.type === "message" ? (
<MessageItem
key={item.id}
direction={item.direction}
message={item.message}
/>
) : (
<AttachmentItem
key={item.id}
direction={item.direction}
thumbnail={item.thumbnail}
fileName={item.fileName}
/>
)
)
);
}, [chats]);
And this is the submit function (using react hook form):
const hookFormSubmit = (data) => {
const chatObject = {
id: chats.length + 1,
direction: "sending",
type: "message",
message: data.messageToSend,
};
setChats((prev) => [...prev, chatObject]);
};
As you can see, every time "chats" gets updated, it triggers useEffect and it maps all "chats" to "chatItems". Does it cause performance issues? Or does list key handles it and only maps components that are changed or new? Should I do it this way or directly using "setChatItems" to update my chat app view?
I have to mention that code works properly right now, but the thing is that I wanna make sure that I am doing it the right way so it won’t cause problems if my chats data gets larger.
Thank you.
2
Answers
The
chatItems
is derived data that can be calculated based on thechats
state. You don’t need thechatItems
state and call setter function inuseEffect
hook, it will cause a re-render.Instead,
useMemo()
is the best way for this situation. See you-might-not-need-an-effect#caching-expensive-calculationsStoring components in state is not recommended, because it makes your state larger and harder to manage.
You can store the data in the
chats
state and then map them to components in therender
function. For example, in yourhookFormSubmit
function, you can add a newchat
object to thechats
array:For example:
Then, in your
return
statement, you can map the chats array toMessageItem
orAttachmentItem
components, depending on the type of each chat:This way, you avoid storing components in state and using
useEffect
unnecessarily. You also make your code more readable and maintainable.You can also use
React.memo()
to wrap yourMessageItem
and AttachmentItemcomponents
, so that they only re-render when their props change. This can prevent unnecessary re-rendering of the components when the chats array changes, but the props of the components remain the same. Please see React Hooks API Reference for more details.For example: