Reputation: 2204
I am trying to create multiple axios requests in socket.io. If I have simultaneously:
socket.emit ("Emit1", req1.data);
socket.emit ("Emit2", req2.data);
socket.emit("Emit2", req2.data);
works. socket.emit ("Emit1", req1.data);
does not work.
When I remove socket.emit("Emit2", req2.data);
--> emit1
works.
How to combine it so that it works simultaneously?.
Can I create two servers. One supporting the first component and request get url1
and a second server that supports requesturl2
?
const Emit = async socket => {
try{
const [req1, req2] = await Promise.all([
axios.get(url1, {
headers: {
}
}),
axios.get(url2, {
headers: {
'Authorization': `Bearer ${token}`
}
})
]);
socket.emit("Emit1", req1.data);
socket.emit("Emit2", req2.data);
}
catch(error){
console.log(error)
}
};
Client
First component:
import socketIOClient from "socket.io-client";
componentDidMount() {
axios.get
axios({
url,
method: "GET",
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(res => {
this.setState({
scores: res.data,
activeTab: res.data[0].id
});
})
.catch(error => {
console.log(error);
})
}
componentDidUpdate(prevProps, prevState) {
const endpoint = 'http://127.0.0.1:3000';
if (prevState.scores !== this.state.scores) {
const socket = socketIOClient(endpoint);
socket.on("Emit1", data => this.setState({
scores: data
}));
}
}
Second component:
import socketIOClient from "socket.io-client";
componentDidMount() {
axios.get
axios({
url,
method: "GET",
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(res => {
this.setState({
abcd: res.data
});
})
.catch(error => {
console.log(error);
})
}
componentDidUpdate(prevProps, prevState) {
const endpoint = 'http://127.0.0.1:3000';
if (prevState.abcd !== this.state.abcd) {
const socket = socketIOClient(endpoint);
socket.on("Emit2", data => this.setState({
abcd: data
}));
}
}
Upvotes: 0
Views: 4719
Reputation: 21317
I've been working on your question for a while now and this are my conclusions:
I've reconstructed your backend this way:
const express = require('express')
const app = express()
const http = require('http').createServer(app)
const io = require('socket.io')(http)
const port = 3003
app.use(express.json())
app.get('/emit', async({ res }) => {
const [data1, data2] = await Promise.all([fakeApiCall(1), fakeApiCall(2)])
io.emit('Emit1',data1)
io.emit('Emit2',data2)
res.status(200).json('emitted')
})
const fakeApiCall = id =>{
return new Promise((resolve, reject) =>{
setTimeout(() => resolve(`data${id}`), 3000)
})
}
http.listen(port, () => console.log('listening on port ' + port))
Essencially that's exactly what you are doing, and works just fine, both events are emmited after Promise.all
solves all promises.
After that I've made a version of your frontend:
App.js:
import React from 'react'
import ComponentA from './ComponentA'
import ComponentB from './ComponentB'
const App = () => {
return (
<>
<ComponentA />
<ComponentB />
</>
)
}
export default App
Component A :
import React from 'react'
import socketIOClient from 'socket.io-client'
class ComponentA extends React.Component {
state = {
data: null
}
componentDidMount(){
setTimeout(() => this.setState({data: 'bla'}), 2000)
}
componentDidUpdate(prevProps, prevState) {
const endpoint = 'http://127.0.0.1:3003';
if (prevState.data !== this.state.data) {
const socket = socketIOClient(endpoint);
socket.on("Emit1", data => this.setState({ data }))
}
}
render() {
const { data } = this.state
return (
<div>
{data}
</div>
)
}
}
export default ComponentA
Component B :
import React from 'react'
import socketIOClient from 'socket.io-client'
class ComponentB extends React.Component {
state = {
data: null
}
componentDidMount(){
setTimeout(() => this.setState({data: 'bla'}), 2000)
}
componentDidUpdate(prevProps, prevState) {
const endpoint = 'http://127.0.0.1:3003';
if (prevState.data !== this.state.data) {
const socket = socketIOClient(endpoint);
socket.on("Emit2", data => this.setState({ data }))
}
}
render() {
const { data } = this.state
return (
<div>
{data}
</div>
)
}
}
export default ComponentB
And surprisingly... It works just fine! So, what is the difference here? Everything looks the same (how the events are emitted, how the listener is only inserted in componentDidUpdate
, how the state changes after an async call in componentDidMount
).
So the only thing that can possibly be interfering is the axios call you make inside componentDidMount
, cause in both components the io.listen
isn't setted at componentDidMount
how it should be (I assume you have reasons for that), so both components MUST update the state before the event is emmited, otherwise if the properties data
or abcd
don't get updated in time the event listener will be called after the backend emits the data. And your claim about how if you omit Emit2
Emit1
will work just fine. But, what about omit Emit1
? Emit2
will work as well? Looks like a race condition, something in componentA
's componentDidMount
is preventing componentB
from updating or vice-versa
Place the io's listeners in componentDidMount
in both components to determine if this is the case. Cause honestly, I couldn't think in any other problem that may be causing this.
Upvotes: 1