多次重新渲染组件

时间:2020-07-02 21:08:26

标签: javascript arrays reactjs socket.io react-hooks

在编写套接字io聊天应用程序时,我遇到了React组件的多个重新渲染问题。后端位于Nodejs上,可以正确发送所有消息,而在客户端接收新消息时,每次我从套接字收到新消息并尝试更新消息列表时,我的组件都会重新渲染(x + 7)次。我还尝试将 useEffect 依赖项参数保留为空数组,但是,在这种情况下,我每次都会获取空数组,而它应该已经是包含现有消息的数组。我在下面发布了代码,并在浏览器的控制台上截图了。如果有人可以解释如何解决此问题,将非常高兴。

enter image description here

import React,{useState, useContext, useEffect} from 'react';
import MessageItem from './MessageItem';
import {Context} from '../../store/Store';
import socket from '../../utils/socket';
import {actions} from '../../reducers/actions';
import List from '@material-ui/core/List';
import SpringScrollbars from '../../utils/ScrollBar';

let test = 0;

function MessageFrame() {

    const [state, dispatch] = useContext(Context);
    const [messages, setMessages] = useState([]);

    useEffect(() => {
        socketOnListeners();
        test++;
    }, [messages]);

    const socketOnListeners = () => {

      socket.on("joinCompleted", data => {
        const allMessages = [...messages];
        allMessages.push(data);
        setMessages(allMessages);
      });

      socket.on("room-changed", data => {
        console.log('we changed the roomm', data);
        let allMessages = [];
        allMessages.push(data.message);
        setMessages(allMessages);
        dispatch({type: actions.NEW_ROOM, payload: data.room});
      });

      socket.on('newMsgSaved', data => {
        let allMessages = [...messages];
        console.log('we are initializing', allMessages);
        if(allMessages.length > 1000) allMessages = [];
        allMessages.push(data);
        setMessages(allMessages);
      });

  
      socket.on('user-left-room', data => {
        const allMessages = [...messages];
        allMessages.push(data);
        setMessages(allMessages);
      });

      socket.on('userExit', data => {
        const allMessages = [...messages];
        allMessages.push(data);
      });

      // return () => socket.disconnect();

    }


    return (
        <SpringScrollbars 
            autoHide={true}
            renderView={props => <div style={{padding: '0 25px 0 15px', ...props.style}} />}
            style={{ width: '100%', height: '90vh' }}>
              {test}
            <List>
                {messages.length > 0 ? messages.map((el,idx) => {
                    let direction = 'right';
                    if(el.type === 'system'){
                      direction = 'center';
                    }
                    else if(el.type === 'current'){
                      direction = 'left';
                    }
                    return (
                        <MessageItem key={idx} data={el} direction={direction} />
                    );
                }) : null}
            </List>
        </SpringScrollbars>
    )
}

export default MessageFrame;

2 个答案:

答案 0 :(得分:0)

编辑: 首先需要删除对useEffect的message依赖性,因为它为一个事件创建了许多回调。 其次是在回调中使用setMessage来获取当前更新的message,当您尝试访问套接字中消息的状态时,在回调中它没有为您提供当前的状态,但显示初始化期间的那个。但是,当您通过setMessage回调访问消息时,则会得到最新的message,并且可以将它们堆叠在一起。 这是解决方案:

socket.on('newMsgSaved', data => {
     setMessages(currMessages => {
          let allMessages = [...currMessages];
          if (allMessages.length > 1000) allMessages = [];
          return [...allMessages, data]
     });
});

答案 1 :(得分:0)

useEffect的第二个参数的默认行为是对传入的内容进行浅等检查。您可以通过确保传递相同的数组实例,或者通过传递可以在浅处进行比较的值来解决此问题。数组。 https://github.com/facebook/react/issues/14324

此处为参考文章