<p>react-dnd 可以调用未安装的组件,导致“未捕获错误:找不到有效的 targetId”</p>

创建于 2019-06-02  ·  3评论  ·  资料来源: react-dnd/react-dnd

描述错误
react-dnd 可能会调用一个 collect 函数导致组件卸载,然后对卸载的组件进行另一个 collect() 调用,从而导致未捕获的错误“找不到有效的 targetId”。

Redux 在后端拖放事件的 dispatch() 上在开始时复制所有订阅事件的侦听器,并始终调用它们,而不管哪些 redux 订阅已取消订阅,同时通知订阅者(请参阅 https://stackoverflow.com/questions /43356080/redux-unsubscribe-within-componentwillunmount-still-calls-subscribe-callback)。 这意味着,如果类似 'EndDrag' html5 拖动事件在 react-dnd/src/decorateHandler.tsx:handleChange() 中的 handleChange() 中触发通知,并且第一个 collect() 调用导致卸载组件,则后续卸载的组件可能会在同一事件的后续通知中触发其 collect() 调用。

因此,不变量“预期找到有效目标”被触发,因为该组件已从有效目标 Id 的注册表中有效删除,但通知正在调用未安装的组件。

我在尝试将使用 react-dnd 的 react-sortable-tree 集成到我的应用程序中时发现了这个问题。 您可以在此处查看问题示例和可重新创建的测试用例:https://github.com/frontend-collective/react-sortable-tree/issues/490。 通过在 dragTarget 之外释放 dragSource 取消的拖放每次都会重现此问题。

未捕获的错误和堆栈跟踪粘贴在下面,堆栈跟踪显示连接函数正在调用 monitor.canDrop(),它在卸载的组件上失败。
browser.js:38 Uncaught Invariant Violation:期望找到一个有效的目标。在不变(https://xzoq6xprlz.codesandbox.io/node_modules/invariant/browser.js:38:15)在 DragDropMonitorImpl.canDropOnTarget (https://xzoq6xprlz.codesandbox.io/node_modules/dnd-core/lib/cjs/DragDropMonitorImpl.js:67:9)
在 DropTargetMonitorImpl.canDrop (https://xzoq6xprlz.codesandbox.io/node_modules/react-dnd/lib/cjs/DropTargetMonitorImpl.js:24:41)
在 nodeDropTargetPropInjection (https://xzoq6xprlz.codesandbox.io/node_modules/react-sortable-tree/dist/index.cjs.js:2367:28)
在 DragDropContainer.getCurrentState (https://xzoq6xprlz.codesandbox.io/node_modules/react-dnd/lib/cjs/decorateHandler.js:116:29)
在 DragDropContainer._this.handleChange (https://xzoq6xprlz.codesandbox.io/node_modules/react-dnd/lib/cjs/decorateHandler.js:45:39)
在 handleChange (https://xzoq6xprlz.codesandbox.io/node_modules/dnd-core/lib/cjs/DragDropMonitorImpl.js:27:21)
在调度(https://xzoq6xprlz.codesandbox.io/node_modules/redux/lib/redux.js:220:7)
在 Object.eval [as endDrag] (https://xzoq6xprlz.codesandbox.io/node_modules/dnd-core/lib/cjs/DragDropManagerImpl.js:67:21)
在 HTML5Backend.handleTopDragEndCapture (https://xzoq6xprlz.codesandbox.io/node_modules/react-dnd-html5-backend/lib/cjs/HTML5Backend.js:145:31)
``

解决方法

调用未挂载的组件可能不是正确的行为,因此我在 react-dnd/src/decorateHandler.tsx:handleChange 中添加了一个 if 语句,如果 DecorateHandler 已取消订阅,则删除通知。 附上差异。

diff --git a/packages/react-dnd/src/decorateHandler.tsx b/packages/react-dnd/src/decorateHandler.tsx
index 85385ec..bcd149e 100644
--- a/packages/react-dnd/src/decorateHandler.tsx
+++ b/packages/react-dnd/src/decorateHandler.tsx
@@ -159,6 +159,15 @@ export default function decorateHandler<Props, CollectedProps, ItemIdType>({
                }

                public handleChange = () => {
+                       if (this.disposable.isDisposed) {
+                               console.log("in handleChange")
+                               //because redux takes a snapshot of all subscribers to 
+                               //events when it starts dispatch, it is still possible to call into this even after 
+                               //the subscription has been unsubscribed
+                               //to prevent against calling into unmounted objects, return immediately
+
+                               return
+                       }
                        const nextState = this.getCurrentState()
                        if (!shallowEqual(nextState, this.state)) {
                                this.setState(nextState)
wontfix

最有用的评论

@mx2323这是推进来的吗? 即使是 react-sortable-tree 仍然需要最新的 react-dnd 更新,我认为它正在等待

所有3条评论

此问题已自动标记为陈旧,因为它最近没有活动。 如果没有进一步的活动发生,它将被关闭。 感谢你的贡献。

@mx2323这是推进来的吗? 即使是 react-sortable-tree 仍然需要最新的 react-dnd 更新,我认为它正在等待

我最终没有推动它。

此页面是否有帮助?
0 / 5 - 0 等级