无法在 socket.io 回调 React.js 中调用 setState
Posted
技术标签:
【中文标题】无法在 socket.io 回调 React.js 中调用 setState【英文标题】:Can't call setState inside socket.io callback React.js 【发布时间】:2019-09-21 23:42:27 【问题描述】:我面临以下问题:
在处理状态的 React 组件中,有一个与 socket.io 的 websocket 连接。每当我收到一些事件时,我应该做一些操作并更新组件的状态。示例:
socket.on('some event', () =>
this.aMethod() // this method calls setState()
)
问题是出现以下消息:
Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
但我不在任何地方使用componentWillUnmount
方法。并且组件没有卸载。
如果我将 aMethod
替换为 this.props.aMethod()
并更新将起作用的父组件的状态( aMethod 存在于两个组件中)。问题是这个组件很大,因为它是一个容器,将所有状态移动到父级并使用道具会导致大量重写..
这让我想到应用的反应路线可能存在一些问题。
父组件有以下路由(概念上):
<Switch>
<Route exact path='/user/:id' render=(props) => <User /> />
<Route exact path='/users' render=(props) => <User /> />
</Switch>
我使用render
而不是component
因为我需要传递一些方法作为道具。 React 和 react-router-dom 是 16.x 和 5.0.0 的最新版本。
是否有可能以某种方式“冻结”组件的第一个实例,然后 url 发生变化,我无法再更新状态?如果我在componentWillUnmount()
中控制台记录一条消息,我看不到它正在卸载。
任何想法将不胜感激!
欢迎提问。
【问题讨论】:
请添加完整代码 【参考方案1】:React 告诉你必须删除 componentWillUnmount 中的监听器:
componentWillUnmount()
socket.off('some event');
这是因为:
如果你在 componentDidMount 中添加监听器,你最终会得到多个监听器 当组件被卸载(路由更改)时,“this”和它的上下文绑定不再有意义,但是回调在每次事件发生时都会尝试设置状态表单反应文档:
componentWillUnmount() 在组件被调用之前立即调用 卸载并销毁。在此方法中执行任何必要的清理, 例如使计时器无效、取消网络请求或清理 添加在 componentDidMount() 中创建的所有订阅。
参考:https://reactjs.org/docs/react-component.html?utm_source=caibaojian.com#componentwillunmount
另一个更好地理解问题的资源:
https://advancedweb.hu/2016/01/05/global-listener-patterns-in-react/
【讨论】:
你是对的..我在构造函数中有套接字连接,但我从未断开从带有off
的事件中删除侦听器的连接。仍然不确定这如何影响setState
,为什么this
有效以及为什么this.props
也有效:) 任何进一步的指导或链接都会有所帮助。
我还在componentWillUnmount
中使用了.disconnect()。如果我想保持连接打开并在注销时关闭它会有什么问题吗?
一旦你删除了监听器,你就完成了。我已经添加了 react docs 的相关部分以上是关于无法在 socket.io 回调 React.js 中调用 setState的主要内容,如果未能解决你的问题,请参考以下文章
Socket.IO 在一个房间内多次发射(与 React.js 一起使用)
如何通过 Express JS 服务器使 React JS 和 Socket IO 连接在一起?