簡體   English   中英

React 功能組件隨着數組狀態的變化呈指數級重新渲染

[英]React Functional Component Re-renders exponentially with array state change

我的一個功能組件有問題。 基本上,它在狀態中有一個消息數組; 當服務器發送一條新消息時,狀態應該通過將新消息推送到數組中來改變。 問題隨着陣列的增長而出現。 對於添加到數組中的每個項目,它都會以指數方式重新渲染。 例如。 對於數組中的一條消息,它呈現一次,對於兩條消息,它呈現兩次,對於三條消息,它呈現六次,等等......通常,這不會是一個大問題。 但是,在 useEffect 函數中,我進行了 api 調用,因此,我需要限制調用該函數的次數,並且還需要限制渲染。 這是組件的代碼,希望這一切都有意義。 謝謝您的幫助!

// Imports here...
let count = 0;

const Chat: React.FC<any> = ({ name, chatRoom, language }) => {
  const [messages, setMessages] = useState<Array<MessageInterface>>([]);
  const [message, setMessage] = useState<string>("");
  const [users, setUsers] = useState<Array<string>>([]);

  useEffect(() => {
    socket = io(ENDPOINT, {
      withCredentials: true,
      extraHeaders: {
        "my-custom-header": "abcd",
      },
    });

    socket.on("connect", () => {
      console.log(`I am now connected to the server with id: ${socket.id}`);
    });

    socket.emit("login", { name, chatRoom, language }, () => {});

    // unmounting
    return () => {
      socket.emit("disconnectFromServer");
      console.log("Disconnected from the server");
      socket.off();
    };
  }, [name, chatRoom, language]);

  useEffect(() => {
// ======== THIS IS THE FUNCTION THAT IS CALLED EXPONENTIALLY======== 
    socket.on("message", (message: MessageInterface) => {
     // This is where the api call would be
      console.log(count);
      count++;
      setMessages([...messages, message]);
    });
  }, [messages]);

  useEffect(() => {
    socket.on("userJoin", (usersFromServer: Array<string>) => {
      setUsers([...users, ...usersFromServer]);
    });
  }, [users]);

  useEffect(() => {
    socket.on("userLeave", (usersFromServer: Array<string>) => {
      setUsers(usersFromServer);
    });
  }, [users]);

  const sendMessage = (evt: React.KeyboardEvent<HTMLInputElement>) => {
    evt.preventDefault();

    if (message) {
      socket.emit("sendMessage", message, () => setMessage(""));
    }
  };

  return name && chatRoom ? (
    <div id="chatOuterContainer">
      <Users users={users} language={language} />
      <div id="chatInnerContainer">
        <InfoBar chatRoom={chatRoom} language={language} />
        <Messages messages={messages} name={name} />
        <Input
          message={message}
          setMessage={setMessage}
          sendMessage={sendMessage}
          language={language}
        />
      </div>
    </div>
  ) : (
    <Redirect to="/" />
  );
};

export default Chat;

useEffect清理時,您需要刪除消息偵聽器:

useEffect(() => {
  const handler = (message: MessageInterface) => {
   // This is where the api call would be
    setMessages([...messages, message]);
  });
  socket.on("message", handler);
  return () => {
    socket.off("message", handler);
  };
}, [messages]);

更好的方法是使用回調表單,以避免需要依賴外部messages變量:

useEffect(() => {
  const handler = (message: MessageInterface) => {
    setMessages(messages => [...messages, message]);
  });
  socket.on("message", handler);
  return () => {
    socket.off("message", handler);
  };
}, []);
  useEffect(() => {
// ======== THIS IS THE FUNCTION THAT IS CALLED EXPONENTIALLY======== 
    socket.on("message", (message: MessageInterface) => {
     // This is where the api call would be
      console.log(count);
      count++;
      setMessages([...messages, message]);
    });
  }, []);

socket.on('message',function) 應該只調用一次。 如果重復調用它,它將堆疊,而不是覆蓋。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM