General
Hello, I'm not sure if this is a problem with the library or with my code, but I feel like the React 18 hook useSyncExternalStore is not supported on the message prop of the Chat component.
What bug do you experience? 🐞
I have a service which provides data for the Conversation component, in the Conversation component I use the react-native-chat-ui Chat component to render the chat. In my first iteration I used React's state hook to supply the messages to the Chat component, but as I have been refining the design I wanted to refactor out the server communication into a separate piece of code. I evaluated that the useSyncExternalStore should do the trick. After rolling out some code for the custom store and trying it out, I'm getting an infinite loop in the React render.
Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
How can it be reproduced? 🤔
Step 1. Define a service to be used with useSyncExternalStore
Step 2. Use the defined service in a component that renders the Chat component
Step 4. Pass the service data to the Chat messages prop.
What behavior is expected? 💡
The Chat component should use the passed prop as the source of the displayed messages and rerender when the external store calls the listener callback.
// ConversationService.ts
export const conversationService = (id: string) => {
let messages : Message[] = [];
let messagesListeners : any[] = [];
let lastMessagesResponse : GetMessagesResponse;
const updateMessages = () => {
const toTimestamp = new Date();
const fromTimestamp = lastMessagesResponse?.latestMessageTimestamp ?? new Date(0);
Server.Conversations.GetMessagesBetween(id, fromTimestamp, toTimestamp)
.then(resp => {
messages = [...messages, ...resp.selectedMessages]
lastMessagesResponse = resp ?? lastMessagesResponse;
emitMessagesChanged();
})
.catch(err => console.error(err));
}
const subscribeMessages = (listener: any) => {
messagesListeners = [...messagesListeners, listener];
return () => {
messagesListeners = messagesListeners.filter(l => l !== listener);
}
}
const getMessagesSnapshot = () => {
return messages?.map(mapMessage) ?? [];
}
const emitMessagesChanged = () => {
for (const listener of messagesListeners) {
listener();
}
}
const sendTextMessage = (message: MessageType.PartialText) => {
Server.Conversations.PostMessage(id, { encryptedTextData: message.text })
.then(_ => updateMessages())
.catch(err => console.error(err));
}
const mapMessage = (message: Message): MessageType.Any => {
if (message.encryptedTextData) {
return {
id: message.timestamp.valueOf().toString(), // WARN: temporary hack, should return id with message dto
type: "text", text: message.encryptedTextData,
createdAt: message.timestamp.valueOf(), author: { id: message.sender.phoneNumber }
};
}
}
return {
messages: {
subscribe: subscribeMessages ,
snapshot: getMessagesSnapshot
}
}
}
// Conversation.tsx
const Conversation = ({ route, navigation }: ConversationProps) => {
const id = route.params.convId;
const service = conversationService(id);
const conversationMessages = useSyncExternalStore<MessageType.Any[]>(service.messages.subscribe, service.messages.snapshot);
return (
<View style={{ flex: 1 }}>
<Chat messages={conversationMessages} />
</View>
);
}
Environment info
Please specify the react, react-native, react-native-chat-ui versions.
react: 18.2.0
react-native: 0.71.6
react-native-chat-ui: 1.4.3
expo: 48.0.11
npx react-native info
output 👇
System:
OS: Windows 10 10.0.22623
CPU: (12) x64 Intel(R) Core(TM) i5-10400 CPU @ 2.90GHz
Memory: 35.52 GB / 63.82 GB
Binaries:
Node: 16.16.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.19 - ~\AppData\Roaming\npm\yarn.CMD
npm: 9.6.4 - C:\Program Files\nodejs\npm.CMD
Watchman: Not Found
SDKs:
Android SDK: Not Found
Windows SDK:
AllowDevelopmentWithoutDevLicense: Enabled
Versions: 10.0.17763.0, 10.0.19041.0
IDEs:
Android Studio: Not Found
Visual Studio: 17.5.33530.505 (Visual Studio Community 2022)
Languages:
Java: 11.0.16.1 - C:\Program Files\Microsoft\jdk-11.0.16.101-hotspot\bin\javac.EXE
npmPackages:
@react-native-community/cli: Not Found
react: 18.2.0 => 18.2.0
react-native: 0.71.6 => 0.71.6
react-native-windows: Not Found
npmGlobalPackages:
*react-native*: Not Found
Platform
Expo Go (managed React Native app)