简体   繁体   中英

useEffect socket.on problem rerendering useState

I'm looking for some help using socket.io-client. I'm having some issues trying to get all messages from the chat server. I'm supposed to get an individual message and I'll need to push to a state. I'm not getting rerender on each message. Is there any way to handle the state and update it? Thanks

import React, {useState, useEffect} from 'react'
import {withRouter} from 'react-router-dom'
import Button from '../core/Button'
import Field from '../core/Field'
import Label from '../core/Label'
import {Container, ScrollContainer} from './StyledComponents'
import useLocalStorageState from '../../hooks/useLocalStorage'
import io from 'socket.io-client'
import {SOCKET_SERVER_CLIENT} from '../../utils/const'
import Profile from '../Profile/Profile'

let socket
const Chat = ({location}) => {
  const [listMessages, setListMessages] = useState([])
  const [message, setMessage] = useState('')

  useEffect(() => {
    const username = location.search.split('=')[1]
    socket = io(`${SOCKET_SERVER_CLIENT}/?username=${username}`)
    return () => {
      socket.disconnect()
    }
  }, [])

  useEffect(() => {
    socket.on('message', message => {
        const auxArr = listMessages
        auxArr.push(message)
        setListMessages(auxArr)
    })
  })

  return (
    <Container>
      {console.log('rerender')}
      <ScrollContainer>
        {listMessages &&
          listMessages.map(infoMessage => (
            <Profile key={infoMessage.time} {...infoMessage} />
          ))}
      </ScrollContainer>
    </Container>
  )
}

export default withRouter(Chat)

const auxArr = listMessages
auxArr.push(message)
setListMessages(auxArr)

This code is mutating the old array, and then setting state with that same array. Function components do a check when setting state to make sure it changed. Since it's the same array before and after, the render gets skipped.

Instead of mutating the state, you will need to copy it:

const auxArr = [...listMessages];
auxArr.push(message);
setListMessages(auxArr);

Since you're basing the new state on the old one, you should also use the callback form of setting state, to eliminate any bugs that might happen if multiple set states happen at right about the same time:

setListMessage(prevMessages => {
  const auxArr = [...prevMessages];
  auxArr.push(message);
  return auxArr;
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM