I'm making a chat app with React and Socket.io and I'm having an issue where it will connect twice on the client side even though on the server side it only logs the connection once. Online the solution it suggests is using useEffect but I can't do that because the client only connects once you click a button so I can't put it inside a function. Once the button is clicked, it goes to a different page so it can't be clicked twice. I'm not sure how to fix this. I tried adding an if statement that checks a separate boolean that is set as true once the button is clicked once but it didn't work.
import React, { Component, useEffect } from 'react';
import { io } from "socket.io-client";
import './App.scss';
const SERVER = "http://127.0.0.1:8000";
var socket;
class Message extends Component {
render() {
if(this.props.received){
return(
<div>
<p className="sender">{this.props.sender}</p>
<p className="received-message">{this.props.content}</p>
</div>
);
}
return(
<div>
<p className="sender">You</p>
<p className="sent-message">{this.props.content}</p>
</div>
);
}
}
class Input extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.props.onChange(event.target.value);
}
handleSubmit() {
this.props.onClick();
}
render() {
return(
<div className="messages-input">
<input type="text" value={this.props.value} onChange={this.handleChange}/>
<button onClick={this.handleSubmit}>Send</button>
</div>
);
}
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
username: null,
usernameValue: '',
messageInput: '',
// messages: [
// {
// content:"this is a test2",
// sender:"Bob",
// received:false
// },
// {
// content:"this is a test5",
// sender:"John",
// received:true
// },
// ]
messages: []
};
this.handleChange = this.handleChange.bind(this);
this.handleUsernameChange = this.handleUsernameChange.bind(this);
this.handleConnect = this.handleConnect.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.scrollToBottom = this.scrollToBottom.bind(this);
}
componentDidMount() {
this.scrollToBottom();
}
componentDidUpdate() {
this.scrollToBottom();
}
scrollToBottom = () => {
if(this.state.username){
this.messagesEnd.scrollIntoView({ behavior: "smooth" });
}
}
handleChange(value) {
this.setState({messageInput: value});
}
handleUsernameChange(event) {
this.setState({usernameValue: event.target.value});
}
handleConnect() {
this.setState({username: this.state.usernameValue});
socket = io(SERVER, { query: "username="+this.state.usernameValue});
}
handleSubmit() {
console.log(this.state.messageInput);
socket.send(this.state.messageInput);
var messages = this.state.messages;
messages.push({
content: this.state.messageInput,
sender: this.state.username,
received: false
});
this.setState({
messageInput: '',
messages: messages
});
}
render(){
var list = <p style={{ textAlign:"center", color: "#787878", fontSize: "large" }}>There are no messages to show</p>;
if(this.state.messages.length !== 0){
list = this.state.messages.map((m) =>
<Message content={m.content} sender={m.sender} received={m.received}/>
);
}
if(!this.state.username){
return(
<div style={{ position: "fixed", top: "50%", left: "calc(50% - 80px)"}}>
<p style={{ textAlign:"center", color: "#787878", fontSize: "large" }}>What is your name?</p>
<input type="text" onChange={this.handleUsernameChange}/>
<div style={{ height: "10px" }}></div>
<button style={{ position: "fixed", display: "block", width: "100px", height: "20px", left: "calc(50% - 50px)" }} onClick={this.handleConnect}>Connect</ button>
</div>
);
}else{
socket.on("connect", () => {
console.log("Connected to server");
});
socket.on("message", data => {
console.log("New message");
console.log(data);
})
return(
<div>
<div style={{ marginBottom: "60px" }}>
{list}
</div>
<Input value={this.state.messageInput} onChange={this.handleChange} onClick={this.handleSubmit}/>
<div style={{ float:"left", clear: "both" }}
ref={(el) => { this.messagesEnd = el; }}>
</div>
</div>
);
}
}
}
export default App;
This is the entire file. If you want to try to recreate it, I can also add the server code but it's pretty simple.