如何从socket.io接收数据时重新呈现组件?

时间:2018-04-23 20:02:33

标签: javascript reactjs socket.io

我正在尝试使用React和socket.io构建一个实时多人游戏,所以当用户登录时,我使用socket.io在服务器端的数组中传递他的名字,然后游戏组件出现,我映射数组以显示所有玩家名称。

所以,第一个玩家登录,他的名字显示在他的窗口上,第二个玩家登录然后得到他的名字+他的窗口上的第一个玩家名字,但第一个玩家的窗口没有更新以显示第二个玩家跟在他后面。

在从socket.io收到数据时,如何在组件上触发渲染?

import React, { Component } from 'react'
import { Button } from 'semantic-ui-react'
import socket from '../api'

class connectedUsers extends Component {
  constructor(props) {
    super(props)

    this.state = {players : []}
  }

  handleData = (data) => {
    this.setState({players: data})
    console.log('handleData ' + data);
  }

  componentDidMount() {
    socket.on('playerList', this.handleData)
  }

  render() {
    console.log('render ' + this.state.players);
    return(
      <div>
        {this.state.players.map(player =>
          <Button basic color='violet' key={player}>{player}</Button>
        )}
      </div>
    )
  }

}

export default connectedUsers

import openSocket from 'socket.io-client'

const socket = openSocket('http://localhost:3001')

export default socket

module.exports = function (io) {
  let players = []

  io.on('connection', socket => {


    socket.on('playerConnected', (player) => {

      players.push(player)

      socket.emit('playerList', players)
    })

    socket.on('disconnect', () => {

       console.log('user disconnected')
     })
  })
 }

import React, { Component } from 'react'
import { Form, Message } from 'semantic-ui-react'
import { Redirect } from 'react-router-dom'
import socket from '../api'

class PseudoForm extends Component {
  state = { name: '', pseudoDispo: false, pseudoValide: true, pseudoNonDispo: false}

  handleChange = (e, { name, value }) => this.setState({ [name]: value })

  handleSubmit = (e) => {
    e.preventDefault()

    const { name } = this.state


    this.setState({pseudoDispo: false})
    this.setState({pseudoNonDispo: false})

    if(name.length > 3) {
      this.setState({pseudoValide: true})

      fetch('/postpseudo', {
        method: "POST",
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({pseudo: name})
      })
        .then(res => res.json())
        .then(data => {
          if(data.pseudoDispo) {
            this.setState({pseudoDispo: data.pseudoDispo})
            socket.emit('playerConnected', name)
          } else {
            this.setState({pseudoNonDispo: true})
            }
          })
        .catch(error => console.error(error))


    } else {
      this.setState({pseudoValide: false})
    }
  }

  render() {
    const { name } = this.state
    const redirectToGame = this.state.pseudoDispo ? <Redirect to={{pathname: '/game'}} /> : true
    return(
      <div>
        {redirectToGame}
          <Form
            success={this.state.pseudoDispo}
            error={this.state.pseudoNonDispo}
            warning={!this.state.pseudoValide}
            onSubmit={this.handleSubmit}
          >
            <Form.Input
              placeholder="Pseudo"
              name="name"
              width={4}
              value={name}
              onChange={this.handleChange}
            />
            <Message
              success
              header='Pseudo Disponible'
            />
            <Message
              error
              header='Pseudo déja pris'
            />
            <Message
              warning
              header='Le pseudo est trop court'

            />
            <Form.Button primary >Envoyer</Form.Button>
          </Form>
      </div>
    )
  }
}

export default PseudoForm

2 个答案:

答案 0 :(得分:1)

好的,现在它适用于io.emit而不是socket.emit + socket.broadcast.emit 这是工作示例

module.exports = function (io) {
  let players = []

  io.on('connection', socket => {


    socket.on('playerConnected', (player) => {

      players.push(player)

      io.emit('playerList', players)
    })


    socket.on('disconnect', () => {

       console.log('user disconnected')
     })
  })
 }

import React, { Component } from 'react'
import ConnectedUsers from '../components/connectedUsers'
import socket from '../api'


class Game extends Component {
  constructor() {
    super()

    this.state = { players: [] }
  }

  componentDidMount() {
    socket.on('playerList', this.handleData)
  }
  
  handleData = (playerList) => {
    this.setState({players: playerList})
  }

  render() {

    return(
      <div>
        <ConnectedUsers list={this.state.players}/>
      </div>
    )
  }
}

export default Game

import React, { Component } from 'react'
import { Button } from 'semantic-ui-react'

class connectedUsers extends Component {
  constructor(props) {
    super(props)


    this.state = {players : []}
  }



  render() {
    console.log('render ' + this.state.players);
    return(
      <div>
        {this.props.list.map(player =>
          <Button basic color='violet' key={player}>{player}</Button>
        )}
      </div>
    )
  }

}

export default connectedUsers

答案 1 :(得分:0)

好的,所以我尝试在服务器端的第一个socket.emit之后添加一个socket.broadcast.emit,并且它可以工作,所有新窗口都会获得更新的新播放列表,但我不明白为什么! 有人对此有所了解吗?

&#13;
&#13;
module.exports = function (io) {
  let players = []

  io.on('connection', socket => {


    socket.on('playerConnected', (player) => {

      players.push(player)

      socket.emit('playerList', players)
      socket.broadcast.emit('playerList', players)
    })


    socket.on('disconnect', () => {

       console.log('user disconnected')
     })
  })
 }
&#13;
&#13;
&#13;