Reputation: 53
I'm trying to build a realtime multiplayer game with React and socket.io, so when the user is logged in i pass his name in an array on server side with socket.io and then the game component shows up and i map the array to display all players name.
So, first player logs in, his name is shown on his window, second player logs in then gets his name + the first player name on his window, but the window of the first player doesnt update to show the second player that logged after him.
Any idea on how to trigger a render on the component when data is received from 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
Upvotes: 2
Views: 1922
Reputation: 53
Ok so now it works with io.emit instead of socket.emit + socket.broadcast.emit Here's the working example
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
Upvotes: 1
Reputation: 53
Ok so i tried adding adding a socket.broadcast.emit after the first socket.emit on server side, and it works, all the new windows get the new list of players on update, but I have no idea why ! Do someone have an idea about this ?
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')
})
})
}
Upvotes: 0