I am still learning and trying out the new features from React 19’s RC.
Recently I’ve started to work on a simple real-time chat-app.
This is how function that is ran using useActionState and uses useOptimistic looks like (inside of Textarea component):
const handleSubmit = (_prevState: string, queryData: FormData) => {
const message = queryData.get("message") as string;
if (user && message) {
startTransition(async () => {
addOptimisticMessage({
$id: "optimistic_message",
...
});
await submitAction(message, attachments);
});
}
};
This is where I actually initialize the useOptimistic inside of a Room component:
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(currentState: MessageObject[], newMessage: MessageObject) => [
newMessage,
...currentState,
],
);
And then this is how I map the array:
{optimisticMessages.map((message: MessageObject, index: number) => (
<Message key={message.$id} message={message} />
))}
Now to describe the problem:
-
Optimistic message is added to the messages array without any problem, it doesn’t cause re-render of the other components.
<- This works just fine and as expected. -
An actual message is added and the optimistic message is removed -> this is where the problem occurs as the optimistic message gets replaced by the actual one from database and a re-render of all the messages occurs.
Now, I am not updating the state of messages inside of the submitAction()
function but I have a listener set up inside of the Room component that whenever a new message is added it updates the state.
useEffect(() => {
if (room && room.$id) {
const unsubscribeMessages = client.subscribe(
`databases.${database}.collections.messages.documents`,
(response) => {
const payload = response.payload as MessageObject;
const messageRoomId = payload.room.$id;
console.log(payload);
if (messageRoomId === room.$id)
setMessages((prevMessages) => [payload, ...prevMessages]);
},
);
return () => {
unsubscribeMessages();
};
}
}, [room?.$id]);
^ When I comment out the addOptimistic()
function in the Textarea component, it works just fine, so the cause of this re-render isn’t inside of this hook.
Ninjonik is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.