Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React功能组件随阵列状态的变化以指数方式重新渲染_Javascript_Arrays_Reactjs_Typescript - Fatal编程技术网

Javascript React功能组件随阵列状态的变化以指数方式重新渲染

Javascript React功能组件随阵列状态的变化以指数方式重新渲染,javascript,arrays,reactjs,typescript,Javascript,Arrays,Reactjs,Typescript,我的一个功能组件出现问题。基本上,它在状态中有一个消息数组;当服务器发送新消息时,状态应该通过将新消息推送到数组中来改变。随着阵列的增长,问题也随之出现。对于添加到数组中的每个项,它都以指数方式重新渲染。例如当数组中有一条消息时,它渲染一次,对于两条消息,它渲染两次,对于三条消息,它渲染六次,等等。。。通常情况下,这不是什么大问题。但是,在useEffect函数中,我正在进行api调用,因此,我需要限制调用该函数的次数,并且还需要限制渲染。下面是组件的代码,希望这一切都有意义。谢谢你的帮助 //

我的一个功能组件出现问题。基本上,它在状态中有一个消息数组;当服务器发送新消息时,状态应该通过将新消息推送到数组中来改变。随着阵列的增长,问题也随之出现。对于添加到数组中的每个项,它都以指数方式重新渲染。例如当数组中有一条消息时,它渲染一次,对于两条消息,它渲染两次,对于三条消息,它渲染六次,等等。。。通常情况下,这不是什么大问题。但是,在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]);
更好的方法是使用回调表单,以避免依赖外部消息变量:

useEffect(() => {
  const handler = (message: MessageInterface) => {
    setMessages(messages => [...messages, message]);
  });
  socket.on("message", handler);
  return () => {
    socket.off("message", handler);
  };
}, []);

当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]);
更好的方法是使用回调表单,以避免依赖外部消息变量:

useEffect(() => {
  const handler = (message: MessageInterface) => {
    setMessages(messages => [...messages, message]);
  });
  socket.on("message", handler);
  return () => {
    socket.off("message", handler);
  };
}, []);
socket.on'message',函数只能调用一次。如果您重复调用它,它将堆叠,而不是覆盖


socket.on'message',函数只能调用一次。如果您反复调用它,它将堆叠,而不是覆盖。

嘿,非常感谢,您的解决方案看起来与上述类似。删除第二个参数中的调用有助于修复它!嘿,非常感谢,看起来您的解决方案与上述类似。删除第二个参数中的调用有助于修复它!