问题
I'm using React and Socket.io but I have an issue. Each character I write in the input field, a new socket id is created and I do not want that to happen. When I remove the setUsername(e.target.value) in the onChange method no socket are created. Here is my code:
Server Side:
const express = require('express'),
app = express(),
http = require('http').createServer(app),
PORT = 5000,
io = require('socket.io')(http);
io.on('connection', (socket) => {
console.log('New client with id: ' + socket.id);
socket.on('disconnect', () => console.log('Disconnected'));
});
http.listen(PORT, (req, res) => console.log('Server has started on port: ' + PORT));
Client Side:
import React, { useEffect, useState } from 'react';
import './App.css';
import io from 'socket.io-client';
import 'materialize-css/dist/css/materialize.min.css';
import M from "materialize-css";
function App() {
const socket = io.connect('http://localhost:5000');
const [username, setUsername] = useState('');
useEffect(() => {
M.AutoInit();
//eslint-disable-next-line
}, []);
const handleSubmit = e => {
e.preventDefault();
};
const onChange = e => {
setUsername(e.target.value);
}
return (
<div>
<form onClick={e => handleSubmit(e)}>
<input id="name" placeholder="Username..." onChange={e => onChange(e)} required />
<button type="submit">Submit</button>
</form>
</div>
);
}
export default App;
Here is the output for each character I write (I typed 'username')
Thank you in advance
回答1:
Right, you're creating a new instance on every re-render because you're defining socket
in the top-level scope of App.
You already have a useEffect
hook in place, so try initiating the connection within that hook instead. Since you've passed an empty array as a second argument to the hook, the code will only be executed once (at the time the component is mounted).
回答2:
Every time you update the state, the App component is rendering so the variables are being initialized again:
const socket = io.connect('http://localhost:5000');
Move the initialization into into useEffect()
and declare the socket variable outside App.js
, or keep it inside App.js but use a useRef()
;
useEffect(() => {
M.AutoInit();
async function connect () {
socket = io.connect('http://localhost:5000');
}
connect();
}, []);
Full code:
let socket = null;
function App() {
const [username, setUsername] = useState('');
useEffect(() => {
M.AutoInit();
async function connect () {
socket = io.connect('http://localhost:5000');
}
connect();
}, []);
const handleSubmit = e => {
e.preventDefault();
};
const onChange = e => {
setUsername(e.target.value);
}
return (
<div>
<form onClick={e => handleSubmit(e)}>
<input id="name" placeholder="Username..." onChange={e => onChange(e)} required />
<button type="submit">Submit</button>
</form>
</div>
);
}
export default App;
来源:https://stackoverflow.com/questions/58922995/react-and-socket-io-usestate-generates-new-socket-connection-onchange-in-input