Correct way to use WebSockets with React Native
I am new to React Native but very familiar with React. As a beginner, I am looking to establish a connection between a cloud server and interactive with websites as I saw in the documentation. Unfortunately there is no decent example to help me. This is all I have so far:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button
} from 'react-native';
export default class raspberry extends Component {
constructor(props) {
super(props);
this.state = { open: false };
this.socket = new WebSocket('ws://127.0.0.1:3000');
this.emit = this.emit.bind(this);
}
emit() {
this.setState(prevState => ({ open: !prevState.open }))
this.socket.send("It worked!")
}
render() {
const LED = {
backgroundColor: this.state.open ? 'lightgreen' : 'red',
height: 30,
position: 'absolute',
flexDirection: 'row',
bottom: 0,
width: 100,
height: 100,
top: 120,
borderRadius: 40,
justifyContent: 'space-between'
}
return (
<View style={styles.container}>
<Button
onPress={this.emit}
title={this.state.open ? "Turn off" : "Turn on"}
color="#21ba45"
accessibilityLabel="Learn more about this purple button"
/>
<View style={LED}></View>
</View>
);
}
componentDidMount() {
this.socket.onopen = () => socket.send(JSON.stringify({ type: 'greet', payload: 'Hello Mr. Server!' }))
this.socket.onmessage = ({ data }) => console.log(JSON.parse(data).payload)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('raspberry', () => raspberry);
Everything works fine, but when I click the button to send the message, this is the error I receive:
Unable to send message. Unknown WebSocket ID 1
I also ran a test with a js client and everything worked smoothly. See how I can get this fixed or some source where I can figure it out.
source to share
As per the documentation, you need to add state connected
to your component. And only send anything if the condition is connected
true.
export default class raspberry extends Component {
constructor(props) {
super(props);
this.state = {
open: false,
connected: false
};
this.socket = new WebSocket('ws://127.0.0.1:3000');
this.socket.onopen = () => {
this.setState({connected:true})
};
this.emit = this.emit.bind(this);
}
emit() {
if( this.state.connected ) {
this.socket.send("It worked!")
this.setState(prevState => ({ open: !prevState.open }))
}
}
}
source to share
change the code
socket.send(JSON.stringify({ type: 'greet', payload: 'Hello Mr. Server!' }))
to
this.socket.send(JSON.stringify({ type: 'greet', payload: 'Hello Mr. Server!' }))
it should work.
here is my test code based on your code and RN 0.45 (and the project created with create-react-native-app) connects to the public websocket server wss://echo.websocket.org/
, on my android it works fine and I can see echo websocket server message after button click.
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Button
} from 'react-native';
export default class App extends React.Component {
constructor() {
super();
this.state = {
open: false
};
this.socket = new WebSocket('wss://echo.websocket.org/');
this.emit = this.emit.bind(this);
}
emit() {
this.setState(prevState => ({
open: !prevState.open
}))
this.socket.send("It worked!")
}
componentDidMount() {
this.socket.onopen = () => this.socket.send(JSON.stringify({type: 'greet', payload: 'Hello Mr. Server!'}));
this.socket.onmessage = ({data}) => console.log(data);
}
render() {
const LED = {
backgroundColor: this.state.open
? 'lightgreen'
: 'red',
height: 30,
position: 'absolute',
flexDirection: 'row',
bottom: 0,
width: 100,
height: 100,
top: 120,
borderRadius: 40,
justifyContent: 'space-between'
}
return (
<View style={styles.container}>
<Button onPress={this.emit} title={this.state.open
? "Turn off"
: "Turn on"} color="#21ba45" accessibilityLabel="Learn more about this purple button"/>
<View style={LED}></View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5
}
});
source to share