簡體   English   中英

為什么我的反應元素渲染多次?

[英]Why is my react element rendering many times?

問題:我有以下反應組件。 基本上,我正在構建一個與 socket.io 反應的聊天應用程序

import { io } from 'socket.io-client';

const socket = io(ServerEndURL);
export default function Chat (props) {
    const uuid = props.uuid;
    const classes = useStyles();
    const [open, setOpen] = useState(false);
    const [btnColor, setBtnColor] = useState('white');
    const [activeStatus, setActiveStatus] = useState('Offline');
    const [unreadMsgs, setUnreadMsgs] = useState(0);
    const [msgArr, setMsgArr] = useState([]);
    const chatBtnRef = useRef();
    const chatBoxRef = useRef();
    const msgInputRef = useRef();
    useEffect(() => {
        socket.emit('join', uuid);
        socket.emit('isActive', uuid);
        return () => {
            console.log('removed');
            socket.off('newMsg');
        }
    }, []);

    socket.on('newMsg', msg => {
        console.log('debug');
        let msgs = msgArr.map(msg => msg);
        msgs.push({
            type : 'received',
            msg,
        });
        setMsgArr(msgs);
        if(!open) setUnreadMsgs(unreadMsgs + 1);
        chatBoxRef.current.scrollTop = chatBoxRef.current.scrollHeight;
    });

當服務器在套接字上觸發newMsg事件時,我希望它用新的 msg 更新msgArr state,但我看到console.log('debug')語句運行的次數比預期的要多,而且事情不起作用正如我所期望的那樣。 我的意思是,它應該只對一次。 但它沒有,它運行多次,在某些時候,“次”甚至達到 40。作為新的反應,我不明白為什么會發生這種情況。 因此,如果有人能對這個問題有所了解,我將不勝感激,這讓我好幾天都保持清醒。 我需要幫助。 任何人?

看起來您正在嘗試直接突變 state ,這是您永遠不應該做的。 試試這個:

import { io } from 'socket.io-client';

const socket = io(ServerEndURL);
export default function Chat (props) {
    const uuid = props.uuid;
    const classes = useStyles();
    const [open, setOpen] = useState(false);
    const [btnColor, setBtnColor] = useState('white');
    const [activeStatus, setActiveStatus] = useState('Offline');
    const [unreadMsgs, setUnreadMsgs] = useState(0);
    const [msgArr, setMsgArr] = useState([]);
    const chatBtnRef = useRef();
    const chatBoxRef = useRef();
    const msgInputRef = useRef();
    useEffect(() => {
        socket.emit('join', uuid);
        socket.emit('isActive', uuid);
        return () => {
            console.log('removed');
            socket.off('newMsg');
        }
    }, []);

    socket.on('newMsg', msg => {
        console.log('debug');
        
        // Note: This is a no-op if you don't need to extract info from `msg`
        let msgs = msgArr.map(msg => msg);

        // Update state directly with the new message
        setMsgArr([ ...msgs, { type: 'received', msg }]);

        if(!open) setUnreadMsgs(unreadMsgs + 1);
        chatBoxRef.current.scrollTop = chatBoxRef.current.scrollHeight;
    });

對於問題的第二部分,您告訴 React 您希望將什么呈現到 DOM 中,然后它負責代表您實際更新 DOM。 因此,如果需要,它可能會多次重新渲染您的組件(通常是在 state 已更新時)。 在您的情況下,您為更新 state 的newMsg事件定義事件處理程序,因此當觸發此事件處理程序時,React 會重新呈現您的組件(執行console.log('debug')語句)。

我的假設是,每次 react 渲染組件時,您都會繼續訂閱 newMsg 事件。 如果您的組件重新渲染 40 次,您將有 40 次訂閱您的“newMsg”事件,並且它將運行您的事件回調 40 次。 那說:

改為在 'useEffect' 掛鈎中定義您的 'newMsg' 事件偵聽器。

只要您僅證明一個空數組([])作為您的第二個參數,就可以在您現有的“useEffect”中:

useEffect(() => {

  socket.on('newMsg', ...)

  socket.emit('join', uuid);
  socket.emit('isActive', uuid);
  return () => {
    console.log('removed');
    socket.off('newMsg');
  }
}, []);

或者,如果您的邏輯發生變化並且您“監控”原始“useEffect”中的變化,您可以簡單地將其放在自己的位置。 (示例包括消息數組)

const [msgArr, setMsgArr] = useState([]);
useEffect(() => {
  socket.on('newMsg', msg => {
    setMsgArr([ ...msgArr, { type: 'received', msg }]);
    //Alternative:
    //setMsgArr(msgArr.concat({ type: 'received', msg }));
  })
}, []);

'useEffect' 中的第二個參數只是告訴 react 如果您的第二個參數中的某些內容發生更改,則重新運行效果。 但是,您只想訂閱一次,因此提供了一個空數組,因此它永遠不會看到更改並重新運行效果。

暫無
暫無

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

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