【问题标题】:Array empty outside socket.onsocket.on 外部数组为空
【发布时间】:2020-09-25 07:30:38
【问题描述】:
我知道这与 javascript 的异步特性有关,但是让我解释一下这个问题,因为我一直在摸不着头脑。
问题:
我有一些来自服务器的数据。在我的客户端,我有一个this.socket.on,在其中我从服务器获取数据并尝试将其推送到我在套接字连接开始之前实例化的数组中。我需要将数据保留在套接字连接之外。
这里是代码...任何帮助将不胜感激:
componentDidMount() {
this.table_data = [];
// GET ALL EARTHQUAKES
this.socket = io('localhost:9000', {reconnection: true});
this.socket.on('all_quakes_event', (data) => {
if (data) {
data.features.forEach((el, idx) => {
this.table_data.push(
{
key: el.id,
mag: el.properties.mag,
time: moment(el.properties.time).format('MMMM Do YYYY, h:mm:ss a'),
time_readable: moment(el.properties.time).startOf('hour').fromNow(),
title: el.properties.title
},
)
});
} // END IF
console.log(this.table_data); // GOOD
}); // END SOCKET EVENT
console.log(this.table_data); // EMPTY
}
【问题讨论】:
标签:
javascript
node.js
reactjs
asynchronous
socket.io
【解决方案1】:
将套接字功能放在不同的函数中,并从 do mount 调用该函数。您必须在卸载期间断开连接,否则同一客户端将有多个套接字连接。寻找 hoc 模式以将套接字连接公开给多个组件(稍后您将需要)。
您是否也在构造函数中启动了 this.socket ?我很确定这会与 await io.connect() 一起使用。
【解决方案2】:
将table_data 存储在组件状态中,然后使用setState(或者,在功能组件中,useState 挂钩)对其进行更新:
state = {
table_data: []
}
componentDidMount() {
// GET ALL EARTHQUAKES
this.socket = io('localhost:9000', {reconnection: true});
this.socket.on('all_quakes_event', (data) => {
if (data) {
const newData = data.features.map((el, idx) => {
return {
key: el.id,
mag: el.properties.mag,
time: moment(el.properties.time).format('MMMM Do YYYY, h:mm:ss a'),
time_readable: moment(el.properties.time).startOf('hour').fromNow(),
title: el.properties.title
}
});
this.setState({ table_data: [...this.state.table_data, ...newData] }) // not sure exactly what you want to do with new data vs existing state, but this pattern should work regardless.
} // END IF
console.log(this.table_data); // GOOD
}); // END SOCKET EVENT
console.log(this.state.table_data); // will be empty until some data comes in from the socket.
}
【解决方案3】:
这里需要注意两点:
- 维护一个状态并用新数据更新它。 (@EthanLipkind 已经介绍过了)
-
componentDidMount 只执行一次。您的console.log(this.state.table_data) 将始终为空。在 render 方法中执行 console.log,当你从服务器接收到新数据时,你会看到更新的数据。
附加说明 - 在componentWillUnmount 中注销监听器(如果尚未完成)
componentWillUnmount() {
this.socket.close();
}