I'm using the '@microsoft/signalr' react-native npm package to do a SignalR implementation between a .NETcore 6 api and react-native mobile app. The feature I am trying to use signal R for is a user chat instant messaging feature. I have used the same API and same code in a previous xamarin mobile app and everything worked flawlessly. So I know this is not an API issue.
I wrote the API followed several guides and connections seem to be setup correctly. I can even see message updates in my mobile app after a user sends a new message.
The problem I am having is I am not getting real-time updates from signal R for the messages. I have to refresh my page which triggers my original query for messages. I have exhausted all guides and need help.
I tried other signal R npm packages before this, but '@microsoft/signalr' seemed the most straight forward and was the only one I could get to work.
I expect to see real-time message updates between devices when a user sends a new message. I should see these updates regardless of device type. ie: Android Emulator, Desktop, Android Phone, iPhone, or iPhone simulator
I am including some client-side errors that I'm not entirely sure are from the signal R implementation but they have surfaced since I included the code so maybe they can help identify the problem.
Here is my my react component code...
export default class UserChatComponent extends React.Component{
state = {
user: this.props.user,
sessionItem: this.props.sessionItem,
messages: [],
newMessage: ''
}
componentDidMount() {
const asyncFunc = async ()=>{
const messages = await new UserChatHandler().GetUserChatSessionMessages(this.state.sessionItem.sessionId);
this.setState({ messages: messages });
}
asyncFunc();
const URL = env.api_base_url +'ChatHub';
let connectionBuilder = new signalR.HubConnectionBuilder()
.withUrl(URL, {
//skipNegotiation: true,
//configureLogging: "warn",
//withHandshakeResponseTimeout: 3000000,
//transport: signalR.HttpTransportType.WebSockets
//,headers : {jwtBearer: tokenValue}
});
if(env.name === 'DEBUG') connectionBuilder.configureLogging(signalR.LogLevel.Debug);
this.connection = connectionBuilder.build();
//this.connection.serverTimeoutInMilliseconds = 1000000;
this.connection.on('SendMessage', (arg1) => {
//console.log('connection.on',arg1)
});
this.connection.start()
.then(() => {
//console.log("Connected");
}).catch((error) => {
//console.log("Failed: "+ error);
});
}
componentWillUnmount() {
this.connection.stop()
.then(() => {
console.log('My Connection stopped.');
})
.catch((error) => {
console.log("Failed: "+ error);
});
// fix Warning: Can't perform a React state update on an unmounted component
this.setState = (state,callback)=>{
return;
};
}
handleNewMessage = (text) => {
this.setState({ newMessage: text});
}
sendMessage(){
this.connection.invoke("SendMessage",
{
sessionId: this.state.sessionItem.sessionId,
senderUserId: this.state.user.id,
message: this.state.newMessage
}).then(msg => {
console.log('invoke', msg);
let arr = [];
let msgs = this.state.messages.concat(arr)
msgs.push(msg);
this.setState({
messages: msgs,
newMessage: ''
});
}).catch((error) => alert(error));
}
onReportClicked(){
PubSub.publish(PubSubEvents.ShowGlobalModal,
{ show: true, type: ModalTypes.UgcCompliance, userInfo: this.state.user, data: this.state.sessionItem.sessionMembers[0]});
}
render(){
return (
<View style={appStyles.userChatContainer}>
<View style={localStyles.messagesContainer} >
<ScrollView ref={scrollView => this.scrollView = scrollView}
onContentSizeChange={( contentWidth, contentHeight ) => {
this._contentHeight = contentHeight;
this.scrollView.scrollTo({ y: this._contentHeight , animated: true})
}}>
{this.state.messages &&
this.state.messages.map((msg, _index) =>
this.state.user.id == msg.ownerId ?
(<View key={_index} style={localStyles.userMessageViewContainer} >
<Text>{msg.ownerFullname}</Text>
<View style={localStyles.userTextContainer}>
<Text style={localStyles.userText} >{msg.message}</Text>
</View>
</View>) :
(<View key={_index} style={localStyles.otherMessageViewContainer} >
<Text>{msg.ownerFullname}</Text>
<View style={localStyles.otherUserTextContainer}>
<Text style={localStyles.otherUserText} >{msg.message}</Text>
</View>
</View>)
)
}
</ScrollView>
</View>
<View style={localStyles.newMessageContainer} >
<View style={[{ flex: 1 }, appStyles.justifyAlignCenter ]}>
<TouchableOpacity
onPress = {
() => { this.onReportClicked(); }
}>
<Icon name="more-vert" size={40} color="#7575CF" />
</TouchableOpacity>
</View>
<View style={[{flex: 6 }, appStyles.justifyAlignCenter ]} >
<TextInput style = {[appStyles.input, localStyles.input]}
underlineColorAndroid = "transparent"
placeholder = "Message..."
placeholderTextColor = "#5453A6"
autoCapitalize = "none"
value={this.state.newMessage}
onChangeText = {this.handleNewMessage} />
</View>
<View style={[{ flex: 1, padding: 10 }, appStyles.justifyAlignCenter ]}>
<TouchableOpacity
onPress = {
() => { this.sendMessage(); }
}>
<Icon name="send" size={40} color="#7575CF" />
</TouchableOpacity>
</View>
</View>
</View>
);
}
}
EDIT: I debugged my api as well and verified there is indeed a connection being established between my emulator and a real device. Below is a screenshot of the connections property of the SignalR client.