React socket io客户端发送两次到节点服务器



我正在制作一个react应用程序与节点作为后端。它们使用socket-io进行通信。问题是,我有一个问题,反应和emit发送数据到节点,但做了两次,从而使双重提交。例如,对于登录表单,终端输出如下所示:

[nodemon] starting `node --trace-warnings central-server.js`
web server running on port 5000
client GuRD1JAb_J1xn4O4AAAB successfully connected
{ CompanyID: 'BigCompany', Password: 'SecretPassword' }
{ CompanyID: 'BigCompany', Password: 'SecretPassword' }

这是前端应用程序:

import { useState } from "react";
import Form from "./components/Signup-Form.js";
import { io } from "socket.io-client";
const socket = io("http://192.168.43.118:5000", {
    withCredentials: true,
    extraHeaders: {
        "react-client": "react-client",
    },
});
function App() {
    const [userData, setUserData] = useState({});
    if (Object.entries(userData).length === 0) {
        return (
            <div className="App">
                <div className="textContainer">
                    <h1>Welcome</h1>
                    <h3>You can Log in or Sign Up here</h3>
                </div>
                <Form setUserData={setUserData} />
            </div>
        );
    } else {
        socket.emit("signup", userData);
        return <p>Data sent successfully</p>;
    }
}
export default App;

服务器:

var express = require("express");
var app = express();
var server = require("http").Server(app);
const dotenv = require("dotenv");
dotenv.config();
const WS_PORT = process.env.PORT || 5000;
const io = require("socket.io")(server, {
    cors: {
        origin: ["http://localhost:3000", "http://192.168.43.118:3000"],
        methods: ["GET", "POST"],
        transports: ["websocket", "polling", "flashsocket"],
        allowedHeaders: ["react-client"],
        credentials: true,
    },
});
io.on("connection", (socket) => {
    console.log(`client ${socket.id} successfully connected`);
    socket.on("signup", (data) => {
        console.log(data);
    });
});
server.listen(WS_PORT, () => console.log("web server running on port", WS_PORT));

App.js文件是目前唯一使用套接字的文件。此外,当我保存文件和服务器自动重新加载时,我得到客户端创建连接3次,而不是仅仅一次。

您不应该在呈现代码中执行异步或事件驱动的操作。每次你的App组件被渲染(例如当状态改变时),它也会再次执行你的socket.emit,如果userData仍然是空的。

作为什么导致App渲染两次,我不能从你的代码告诉。但是你应该假设React可以随时重新渲染你的组件,所以尽量避免这样的问题。

您可以使用React.useEffect[]的依赖数组,以便在组件挂载时仅执行一次操作。在您的情况下,最好只是有一个常规的回调:

import { useEffect, useState } from "react";

function App() {
    const [dataSent, setDataSent] = useState(false);
    const sendData = (data) => {
        if (dataSent) return; // Just to make sure
        socket.emit('signup', data);
        setDataSent(true);
    };
    // If you want to actuall wait for a response to display:
    const [response, setResponse] = useState(undefined);
    useEffect(() => {
        socket.on('signup-response', setResponse);
        return () => {
            // This function gets called when the effect gets retriggered
            // (which never happens because of the [] dependency array)
            // or if the component gets unmouted.
            // We remove the event listener here:
            socket.off('signup-response', setResponse);
        };
    }, []);
    if (response) return <p>Got response: {response}</p>;

    if (dataSent) {
        return <p>Data sent successfully</p>;
    } else {
        return (
            <div className="App">
                <div className="textContainer">
                    <h1>Welcome</h1>
                    <h3>You can Log in or Sign Up here</h3>
                </div>
                <Form setUserData={sendData} />
            </div>
        );
    }
}

我添加了一种方式,让您侦听来自服务器的响应。您可以将此用于任何数据/事件,服务器也可以多次发送这些数据/事件。

最新更新