React Hooks 首先在 Websockets 中发送消息

React Hooks Sending message at first in Websockets

我无法在后续点击后发送消息,如果我第一次点击按钮它正在向服务器发送消息,之后它不再向服务器发送消息。

import { useEffect, useState, useRef } from "react";

import Header from "../src/Components/Header";
import ChatHistory from "../src/Components/ChatHistory";
import ChatArea from "../src/Components/ChatArea";

function App() {
  const [messages, setMessages] = useState([]);

  const testValue = { messages, setMessages };

  const socket = useRef(null);

  const renderCount = useRef(0);

  const sendMessage = (msg = "test") => {
    if (socket.current) {
      socket.current.send(msg);
    }
    addMessages(msg);
  };

  const addMessages = (msg) => {
    setMessages((prev) => [...prev, msg]);
  };

  useEffect(() => {
    socket.current = new WebSocket("ws://localhost:8001/ws");
    socket.current.onmessage = (msg) => {
      addMessages(msg);
    };
  }, []);

  useEffect(() => {
    return () => {
      if (socket.current) {
        socket.current.close();
      }
    };
  }, [socket]);

  console.log("i am rendering");

  return (
    <>
      <Header />
      <ChatHistory chatHistory={messages.current} />
      <div>
        <button onClick={sendMessage}>Send</button>
      </div>
    </>
  );
}

export default App;

上面提到的一个是我的代码,当第一次点击发送按钮时,它会触发消息到服务器,在另一次后续点击后它不会触发消息到服务器。需要帮助。

你的第二个 useEffect 实际上在第一次渲染后关闭了连接,这是不必要的。

此外,您实际上并不需要将套接字实例保存在 ref 中,通常您需要一个实例:

const socket = new WebSocket("ws://localhost:8001/ws");

function App() {
  const [messages, setMessages] = useState([]);

  const addMessages = (msg) => {
    setMessages((prev) => [...prev, msg]);
  };

  const sendMessage = (msg = "test") => {
    socket.send(msg);
    addMessages(msg);
  };

  // Setup
  useEffect(() => {
    socket.current.onmessage = addMessages;
  }, []);

  // Runs on App unmount, means on closing the application
  useEffect(() => {
    return () => {
      socket.close();
    };
  }, []);

  return (
    <>
      <Header />
      <ChatHistory chatHistory={messages.current} />
      <div>
        <button onClick={sendMessage}>Send</button>
      </div>
    </>
  );
}
useEffect(() => {
    return () => {
      if (socket.current) {
        socket.current.close();
      }
    };
}, [socket]);

每次套接字发生变化时,您将其关闭
尝试在定义 socket

的同一个 useEffect 中取消 mont
 useEffect(() => {
    if (!socket.current) {
        socket.current = new WebSocket("ws://localhost:8001/ws");
        socket.current.onmessage = (msg) => {
          addMessages(msg);
        };
    }
    return () => {
      if (socket.current) {
        socket.current.close();
      }
    };
  }, [socket]);

请注意 useRef 不是这种情况下的最佳选择,请改用 useState

这是有效的,但我不确定我做错了什么。

import { useEffect, useRef, useState } from "react";

import Header from "./Components/Header";
import ChatHistory from "./Components/ChatHistory";

function App() {
  const [chatHistory, setChatHistory] = useState([]);
  const [isOnline, setIsOnline] = useState(false);
  const [textValue, setTextValue] = useState("");

  const webSocket = useRef(null);

  webSocket.current = new WebSocket("ws://localhost:8001/ws");

  useEffect(() => {
    setTimeout(() => {
      if (webSocket.current.readyState === WebSocket.OPEN) {
        setIsOnline(true);
      }
      if (webSocket.current.readyState === WebSocket.CLOSED) {
        setIsOnline(false);
        setChatHistory([]);
      }
    }, 5);
  }, [webSocket.current]);

  const sendMessage = () => {
    if (webSocket.current.readyState === WebSocket.OPEN) {
      setChatHistory([...chatHistory, textValue]);
      webSocket.current.send(textValue);
    }
  };

  return (
    <>
      <div className="App">
        <Header onLine={isOnline} />
        <ChatHistory chatHistory={chatHistory} />
        <input
          type="text"
          onChange={(e) => setTextValue(e.target.value)}
          value={textValue}
          placeholder="Type Message..."
        />
        <button onClick={sendMessage}>Hit</button>
      </div>
    </>
  );
}

export default App;