无法在 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的主要内容,如果未能解决你的问题,请参考以下文章

React.js JWT Socket.io 身份验证

Socket.IO 在一个房间内多次发射(与 React.js 一起使用)

如何通过 Express JS 服务器使 React JS 和 Socket IO 连接在一起?

是否可以将 React Native 与 socket.io 结合使用

socket.io 发出回调合适吗?

如何在 socket.io CLIENT 上使用回调?