钩子回调时状态不正确

IT技术 reactjs socket.io
2021-05-01 02:12:08

我正在使用 socket.io 和 react hooks 编写一个聊天客户端。消息历史记录 (chatMessages) 在addMessage(收到消息事件时)被调用时不正确(总是一个空数组)。chatMessages确实更新(正确),但在下一次调用时它是空的。不应该有任何其他变量命名 chatMessages并且消息在父类中(set 钩子起作用,所以我不明白为什么状态应该是无效的)。状态似乎也不会再次更新,因此它似乎是添加消息中的某些内容。

import React, { useState, useCallback, useEffect } from "react";
import "./styles/chat.css";
import { uuidv4 } from "./utils/utils";
const SERVER_URL = "http://localhost:3337";
const io = require("socket.io-client");


function ChatManager(props) {
  // How to handle sockets (where do we store them)
  const [UId, setUId] = useState("");
  const [socket, setSocket] = useState(null);
  const [chatMessages, setChatMessages] = useState([]);
  const [role, setRole] = useState("Role");
  const useForceUpdate = () => useState()[1];
  function displayMessage(msg) {
    if (UId) {
      if (msg.user === UId) {
        return (
          <article class="msg-container msg-self" id="msg-0">
            <div class="msg-box">
              <div class="flr">
                <div class="messages">
                  <p class="msg" id="msg-0">
                    {msg.message}
                  </p>
                </div>
              </div>
            </div>
          </article>
        );
      } else {
        return (
          <article class="msg-container msg-remote" id="msg-0">
            <div class="msg-box">
              <div class="flr">
                <div class="messages">
                  <p class="msg" id="msg-0">
                    {msg.message}
                  </p>
                </div>
              </div>
            </div>
          </article>
        );
      }
    }
  }

  function addMessage(msg) {
    console.log("message: ");
    console.log(msg);
    const newMessages = [...chatMessages];
    console.log(chatMessages);
    newMessages.push(msg);
    console.log(newMessages);
    setChatMessages(newMessages);
    console.log("Message added");

  }

  useEffect(() => {
    console.log("did mount");
    if (!socket) {
      setUId(uuidv4());
      console.log("Set UId");
      setSocket(io.connect(SERVER_URL));
      console.log("Socket mounted");
    } else {
      console.log("Socket emit");

      socket.emit("join", {
        uid: UId,
        tid: "Task ID, add later",
        role: role
      });

      socket.on("error", function(err) {
        console.log("received socket error:");
        console.log(err);
      });

      socket.on("message", function(msg) {
     addMessage(msg);
      });
    }
    return () => {
      console.log("Unmounting");
      if (socket) {
        socket.emit("leave", {
          uid: UId,
          tid: "Task ID, add later",
          role: role
        });
        console.log("Leaving message sent");
      }
    };
  }, [socket]);

  function sendMessage() {
    const msg = "Test message";
    socket.emit("usr_input", {
      uid: UId,
      tid: "Task ID, add later",
      message: msg,
      role: role
    });

    console.log("Message sent");
  }

return (
    <div>
      <h1> Here is the chatbox </h1>
      <ChatBox 
      sendMessage={sendMessage} 
      chatMessages={chatMessages}
      displayMessage={displayMessage}/>
      <h1> EOF </h1>
    </div>
  );
}

function ChatBox(props) {
  return (
    <section class="chatbox">
      <section id="chat-messages" class="chat-window">
        {props.chatMessages.map( (msg) => {props.displayMessage(msg)})}
      </section>

    <form class="chat-input" onsubmit="return false;">
        <input
          type="text"
          id="message"
          autocomplete="on"
          placeholder="Type a message"
        />
        <button type="button" onClick={props.sendMessage}>
          <svg
            style={{
              width: "24px",
              height: "24px"
            }}
            viewBox="0 0 24 24"
          >
            {" "}
            <path
              fill="rgba(0,0,0,.38)"
              d="M17,12L12,17V14H8V10H12V7L17,12M21,16.5C21,16.88 20.79,17.21 20.47,17.38L12.57,21.82C12.41,21.94 12.21,22 12,22C11.79,22 11.59,21.94 11.43,21.82L3.53,17.38C3.21,17.21 3,16.88 3,16.5V7.5C3,7.12 3.21,6.79 3.53,6.62L11.43,2.18C11.59,2.06 11.79,2 12,2C12.21,2 12.41,2.06 12.57,2.18L20.47,6.62C20.79,6.79 21,7.12 21,7.5V16.5M12,4.15L5,8.09V15.91L12,19.85L19,15.91V8.09L12,4.15Z"
            />{" "}
          </svg>{" "}
        </button>
      </form>

任何想法或解决方法将不胜感激!

2个回答

如果你改变了你之前的状态chatMessages呢?

正如useState钩子功能更新的文档所述:

如果使用先前的状态计算新状态,则可以将函数传递给 setState。该函数将接收先前的值,并返回一个更新的值。

也许您可以尝试以下代码片段:

function addMessage(msg) {
  setChatMessages(previousMessages => {
    return [
      ...previousMessages,
      msg
    ];
  });
}

我希望这有帮助!

我猜您的value是capture,请查看以下内容以获取更多详细信息。

修复步骤:

  1. 创建一个参考 const myFuncRef = useRef(null)
  2. 将 ref.current 设置为您的功能 myFuncRef .current = myFunc
  3. 使用 func ref 调用 onClick={val => myFuncRef .current(val)}

如何获得之前的props或状态?

React Hooks 组件如何捕获值(以及如何使用最新值)