ReactJS+Socket.io数组对比报错:this.state.messages未定义
问题分析与解决方案
这个问题我熟!你遇到的TypeError: undefined is not an object (evaluating 'this.state.messages')本质是**this指向丢失**的问题,我来给你拆解清楚并解决:
为什么会报错?
你在socket.on('updateRooms')里用了普通的function()作为回调,这个函数内部的this并不指向React组件的实例,而是指向了socket事件触发时的默认上下文,自然就访问不到组件的this.state了。
三种可行的解决办法
1. 改用箭头函数(最推荐,写法简洁)
箭头函数不会创建自己的this,它会继承外层作用域(也就是组件构造函数的this,即组件实例)的this,所以能正常访问this.state:
class Servicedesk extends React.Component { constructor(props) { super(props); this.state = { messages: [], }; socket.on('updateRooms', (combMessages) => { // 这里改成箭头函数 console.log(combMessages.length); console.log(this.state.messages.length); let intersection = combMessages.filter(x => this.state.messages.includes(x)); console.log(intersection); }); } }
2. 在构造函数中bind回调函数
通过bind(this)强制把回调函数的this绑定到组件实例,这样无论在哪里调用这个函数,this都指向组件实例:
class Servicedesk extends React.Component { constructor(props) { super(props); this.state = { messages: [], }; // 先把回调函数bind到组件实例的this this.handleUpdateRooms = this.handleUpdateRooms.bind(this); socket.on('updateRooms', this.handleUpdateRooms); } handleUpdateRooms(combMessages) { console.log(combMessages.length); console.log(this.state.messages.length); let intersection = combMessages.filter(x => this.state.messages.includes(x)); console.log(intersection); } }
3. 提前保存this到变量
在回调函数外层把组件的this存到一个变量(比如self),利用闭包保留这个变量的引用,回调内部用self代替this访问state:
class Servicedesk extends React.Component { constructor(props) { super(props); this.state = { messages: [], }; const self = this; // 保存组件实例的this到self变量 socket.on('updateRooms', function(combMessages) { console.log(combMessages.length); console.log(self.state.messages.length); // 这里用self代替this let intersection = combMessages.filter(x => self.state.messages.includes(x)); console.log(intersection); }); } }
额外优化建议
如果你后续需要在组件卸载时断开socket连接,建议把socket监听逻辑放到componentDidMount生命周期里,这样更符合React的组件规范,也方便在componentWillUnmount里移除监听避免内存泄漏:
class Servicedesk extends React.Component { constructor(props) { super(props); this.state = { messages: [], }; this.handleUpdateRooms = this.handleUpdateRooms.bind(this); } componentDidMount() { socket.on('updateRooms', this.handleUpdateRooms); } componentWillUnmount() { socket.off('updateRooms', this.handleUpdateRooms); } handleUpdateRooms(combMessages) { console.log(combMessages.length); console.log(this.state.messages.length); let intersection = combMessages.filter(x => this.state.messages.includes(x)); console.log(intersection); } }
内容的提问来源于stack exchange,提问作者Draity
相关产品推荐
相关产品推荐

