<p>react-dnd pode chamar um componente desmontado causando `Erro não capturado: não foi possível encontrar um targetId válido`</p>

Criado em 2 jun. 2019  ·  3Comentários  ·  Fonte: react-dnd/react-dnd

Descreva o bug
é possível para o react-dnd chamar uma função collect que causa a desmontagem de um componente e, em seguida, fazer outra chamada collect () no componente desmontado, causando um erro não detectado "Não foi possível encontrar um targetId válido '.

Redux em seu envio () de eventos arrastar e soltar backend faz uma cópia de todos os ouvintes para eventos inscritos no início e sempre os chama, independentemente de quais assinaturas redux foram canceladas enquanto notifica os assinantes (consulte https://stackoverflow.com/questions / 43356080 / redux-unsubscribe-within-componentwillunmount-still-calls-subscribe-callback). Isso significa que se algo como um evento de arrastar 'EndDrag' html5 dispara uma notificação em handleChange () em react-dnd / src / decorateHandler.tsx: handleChange (), e a primeira chamada collect () causa a desmontagem de um componente, o o componente desmontado subsequente pode ter sua chamada collect () acionada em uma notificação subsequente do mesmo evento.

Assim, o invariante 'Esperado para encontrar um destino válido' é acionado porque o componente foi validamente removido do registro de IDs de destino válidos, mas a notificação está chamando um componente não montado.

Eu descobri esse problema ao tentar integrar a árvore classificável de reação, que usa a função react-dnd em meu aplicativo. Você pode ver um exemplo do problema e um caso de teste recriável aqui: https://github.com/frontend-collective/react-sortable-tree/issues/490. Um arrastar e soltar que é cancelado ao liberar um dragSource fora do dragTarget reproduz esse problema todas as vezes.

O erro não detectado e o rastreamento de pilha são colados abaixo. O rastreamento de pilha mostra que a função de conexão está chamando monitor.canDrop () que falha em componentes desmontados.
browser.js: 38 Violação invariante não capturada: Esperado encontrar um alvo válido.em invariante (https://xzoq6xprlz.codesandbox.io/node_modules/invariant/browser.js:38:15)em DragDropMonitorImpl.canDropOnTarget (https://xzoq6xprlz.codesandbox.io/node_modules/dnd-core/lib/cjs/DragDropMonitorImpl.js:67:9)
em DropTargetMonitorImpl.canDrop (https://xzoq6xprlz.codesandbox.io/node_modules/react-dnd/lib/cjs/DropTargetMonitorImpl.js:24:41)
em nodeDropTargetPropInjection (https://xzoq6xprlz.codesandbox.io/node_modules/react-sortable-tree/dist/index.cjs.js:2367:28)
em DragDropContainer.getCurrentState (https://xzoq6xprlz.codesandbox.io/node_modules/react-dnd/lib/cjs/decorateHandler.js:116:29)
em DragDropContainer._this.handleChange (https://xzoq6xprlz.codesandbox.io/node_modules/react-dnd/lib/cjs/decorateHandler.js:45:39)
em handleChange (https://xzoq6xprlz.codesandbox.io/node_modules/dnd-core/lib/cjs/DragDropMonitorImpl.js:27:21)
no envio (https://xzoq6xprlz.codesandbox.io/node_modules/redux/lib/redux.js:220:7)
em Object.eval [as endDrag] (https://xzoq6xprlz.codesandbox.io/node_modules/dnd-core/lib/cjs/DragDropManagerImpl.js:67:21)
em HTML5Backend.handleTopDragEndCapture (https://xzoq6xprlz.codesandbox.io/node_modules/react-dnd-html5-backend/lib/cjs/HTML5Backend.js:145:31)
``

Gambiarra

Chamar componentes desmontados provavelmente não é o comportamento correto, então adicionei uma instrução if em react-dnd / src / decorateHandler.tsx: handleChange que descarta a notificação se decorateHandler já tiver sido cancelada. diff anexado.

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

Comentários muito úteis

@ mx2323 foi enviado? Mesmo se fosse a árvore react-sortable-tree ainda precisa das últimas atualizações react-dnd, eu acho que está esperando

Todos 3 comentários

Este problema foi marcado automaticamente como obsoleto porque não teve atividades recentes. Ele será fechado se nenhuma outra atividade ocorrer. Obrigado por suas contribuições.

@ mx2323 foi enviado? Mesmo se fosse a árvore react-sortable-tree ainda precisa das últimas atualizações react-dnd, eu acho que está esperando

eu não acabei empurrando isso.

Esta página foi útil?
0 / 5 - 0 avaliações