React-dnd: Aviso com DragSource aninhado

Criado em 6 abr. 2016  ·  27Comentários  ·  Fonte: react-dnd/react-dnd

Se você tiver um DragSource dentro de um componente que também é um DragSource (ou seja, arraste algo dentro de um draggable), sempre que o componente pai for arrastado, o seguinte aviso aparecerá.

Warning: setState(...): Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.
warning @   modules.js?hash=107dc56…:19491
getInternalInstanceReadyForUpdate   @   modules.js?hash=107dc56…:5476
ReactUpdateQueue.enqueueSetState    @   modules.js?hash=107dc56…:5617
ReactComponent.setState @   modules.js?hash=107dc56…:15132
handleChange    @   modules.js?hash=107dc56…:20844
handleChange    @   modules.js?hash=107dc56…:22861
dispatch    @   modules.js?hash=107dc56…:23568
addSource   @   modules.js?hash=107dc56…:23124
registerSource  @   modules.js?hash=107dc56…:21172
receiveType @   modules.js?hash=107dc56…:21099
receiveProps    @   modules.js?hash=107dc56…:21089
DragSource(NestedComponent) @   modules.js?hash=107dc56…:21062
ReactCompositeComponentMixin.mountComponent @   modules.js?hash=107dc56…:6679
ReactCompositeComponent_mountComponent  @   modules.js?hash=107dc56…:896
ReactReconciler.mountComponent  @   modules.js?hash=107dc56…:5167
ReactMultiChild.Mixin.mountChildren @   modules.js?hash=107dc56…:13562
ReactDOMComponent.Mixin._createContentMarkup    @   modules.js?hash=107dc56…:10901
ReactDOMComponent.Mixin.mountComponent  @   modules.js?hash=107dc56…:10789
ReactReconciler.mountComponent  @   modules.js?hash=107dc56…:5167
ReactCompositeComponentMixin._updateRenderedComponent   @   modules.js?hash=107dc56…:7101
ReactCompositeComponentMixin._performComponentUpdate    @   modules.js?hash=107dc56…:7075
ReactCompositeComponentMixin.updateComponent    @   modules.js?hash=107dc56…:7004
ReactCompositeComponent_updateComponent @   modules.js?hash=107dc56…:896
ReactCompositeComponentMixin.receiveComponent   @   modules.js?hash=107dc56…:6936
ReactReconciler.receiveComponent    @   modules.js?hash=107dc56…:5217
ReactCompositeComponentMixin._updateRenderedComponent   @   modules.js?hash=107dc56…:7093
ReactCompositeComponentMixin._performComponentUpdate    @   modules.js?hash=107dc56…:7075
ReactCompositeComponentMixin.updateComponent    @   modules.js?hash=107dc56…:7004
ReactCompositeComponent_updateComponent @   modules.js?hash=107dc56…:896
ReactCompositeComponentMixin.receiveComponent   @   modules.js?hash=107dc56…:6936
ReactReconciler.receiveComponent    @   modules.js?hash=107dc56…:5217
ReactCompositeComponentMixin._updateRenderedComponent   @   modules.js?hash=107dc56…:7093
ReactCompositeComponentMixin._performComponentUpdate    @   modules.js?hash=107dc56…:7075
ReactCompositeComponentMixin.updateComponent    @   modules.js?hash=107dc56…:7004
ReactCompositeComponent_updateComponent @   modules.js?hash=107dc56…:896
ReactCompositeComponentMixin.performUpdateIfNecessary   @   modules.js?hash=107dc56…:6952
ReactReconciler.performUpdateIfNecessary    @   modules.js?hash=107dc56…:5232
runBatchedUpdates   @   modules.js?hash=107dc56…:5832
Mixin.perform   @   modules.js?hash=107dc56…:6304
Mixin.perform   @   modules.js?hash=107dc56…:6304
assign.perform  @   modules.js?hash=107dc56…:5789
flushBatchedUpdates @   modules.js?hash=107dc56…:5850
ReactUpdates_flushBatchedUpdates    @   modules.js?hash=107dc56…:896
Mixin.closeAll  @   modules.js?hash=107dc56…:6370
Mixin.perform   @   modules.js?hash=107dc56…:6317
ReactDefaultBatchingStrategy.batchedUpdates @   modules.js?hash=107dc56…:10295
enqueueUpdate   @   modules.js?hash=107dc56…:5879
enqueueUpdate   @   modules.js?hash=107dc56…:5460
ReactUpdateQueue.enqueueSetState    @   modules.js?hash=107dc56…:5626
ReactComponent.setState @   modules.js?hash=107dc56…:15132
handleChange    @   modules.js?hash=107dc56…:21121
handleChange    @   modules.js?hash=107dc56…:22861
dispatch    @   modules.js?hash=107dc56…:23568
(anonymous function)    @   modules.js?hash=107dc56…:22100
endDragIfSourceWasRemovedFromDOM    @   modules.js?hash=107dc56…:29563
handleTopDrop   @   modules.js?hash=107dc56…:29860

Um exemplo disso seria:

class ParentDraggable extends React.Component {
    render() {
        return this.props.connectDragSource(
            <NestedDraggable/>
        );
    }
}

//... Skip the code for containers

class NestedDraggable extends React.Component {
    render() {
        return this.props.connectDragSource(
            <div></div>
        );
    }
}

Eu acredito que o problema decorre do fato de que renderizar novamente o componente pai faz com que a chamada de DragSource filha faça uma chamada para setState durante a chamada de função receiveProps.

triage wontfix

Comentários muito úteis

Caso isso ajude alguém: eu encontrei isso quando estava renderizando um componente que era uma fonte de arrastar em minha camada de arrastar personalizada porque era conveniente. Usei o componente arrastar fonte porque era a mesma entidade que eu estava tentando arrastar, então fazia sentido para mim manter o código "DRY" reutilizando-o. Eu não pensei sobre o fato de que ele tinha todo o código dragSource nele - olhando para trás, _é claro_ eu não gostaria de um código de arrastar como a coisa a ser renderizada na camada de arrastar personalizada.

Por fim, divido meu componente em uma versão "arrastável" que envolve o componente base e, em seguida, usei o componente base em minha camada de arrastar personalizada. Sem mais avisos, melhor código! 👍

Todos 27 comentários

: +1:

Você pode fornecer um projeto reproduzindo o problema?

Estou tentando produzir um exemplo simples e estou tendo problemas para reproduzir fora do meu projeto privado em que estou trabalhando. @nihtalak , você tem um repositório no Github que produz o problema?

Aqui está um minúsculo repo exibindo o comportamento descrito: https://github.com/ebakan/react-dnd-nested-bug

Curiosamente, o Component só lança esse erro quando está escutando monitor.getItem() . Se estiver escutando monitor.isDragging() , funcionará corretamente, conforme mostrado neste branch: https://github.com/ebakan/react-dnd-nested-bug/tree/no-error-with-is- arrastando

Ele também gerará o erro ao ouvir monitor.getItemType() : https://github.com/ebakan/react-dnd-nested-bug/tree/error-with-get-item-type

@ebakan - interessante. Estou me perguntando o que está fazendo com que esse bug apareça no meu código, que usa isDragging. Estou fazendo algumas coisas erradas com o draggable aninhado, então pode ser uma manifestação do mesmo bug que você está vendo. Obrigado pela ajuda na reprodução!

Também aninhei draggables, mas não tenho certeza se esse é o problema.
Parece estar criando uma nova loja e o código que está ouvindo. Fiz um vídeo se isso ajudar:
http://screencast.com/t/qCrJRPAS2MYR

Update: encontrei o problema, eu tinha um ouvinte restante, então no meu caso não foi devido ao react-dnd.
Update2: falei muito cedo. Ao remover o ouvinte restante, ainda recebo o aviso.

Acabei de adicionar Dnd a outro componente e notei esse problema mesmo sem componentes de arrastar aninhados ou múltiplos.

Depois de pesquisar um pouco, descobri que o problema está relacionado à camada de arrastar personalizada que renderiza o componente enquanto é arrastado.

Se eu colocar texto em vez do componente que está sendo arrastado, ele funcionará bem. O próprio componente é a origem do arrasto.

@jchristman @hakunin Não tenho draggables aninhados, mas encontrei Cannot update during an existing state transition quando tive um destino de soltar renderizado condicionalmente com base em isDragging . Isso poderia ser o caso em algum dos seus exemplos? Algo mais ou menos assim:

render() {
    var dropZone;
    if (this.props.isDragging) dropZone = <MyDropTarget />;
    return <div>
       <MyDragSource />
       {dropZone}
    </div>
}

Acabou trabalhando em torno dele usando display: none/block para ocultar o alvo em vez de adicionar e remover o componente quando arrastar está ativo.

Acho que esse pode ser o problema. Vou verificar e lhe aviso. Essa é definitivamente a construção que estou usando agora.

Não - estou entendendo o problema quando a "queda" acontece. Em seguida, ele tenta renderizar novamente o componente e lança este aviso.

Recebi o mesmo aviso quando minha visualização de arrastar era um componente que era um DragSource (o que não devo fazer).

@jchristman , você já encontrou uma solução para isso?

Estou trabalhando com dragSources aninhados e de repente comecei a ver este erro ao soltar o recurso aninhado.

Posso fornecer um exemplo, mas gostaria de ver se alguém havia resolvido o problema ou tinha uma solução alternativa adequada.

Recebi o mesmo aviso quando minha visualização de arrastar era um componente que era um DragSource (o que não devo fazer).

Obrigado @arjunu meu aviso foi causado por isso!
Eu ainda tenho isso ocasionalmente, então acho que algum outro motivo deve ser consertado também. Pode ser da minha parte :)

@ gharwood1 , estou apenas vivendo com o problema até que possa ser consertado. Uma vez, passei algumas horas tentando realmente entender esta biblioteca para que eu pudesse puxar a solicitação de uma correção, mas é muito complexo, então segui em frente. Eu simplesmente não tenho tempo ... :-(

@gaearon Não tenho um projeto feito que seja capaz de alguém derrubar, mas acho que posso conseguir fazer um, se necessário.

Basicamente, o que estou tentando fazer aqui é válido:

https://github.com/arackaf/booklist/blob/react-dnd-bug-freeze/react-redux/modules/subjects/components/subjectsList-es6.js

Se eu desabilitar a condicional na linha 64 está tudo bem

if (this.props.draggingSubject){
    effectiveChildren.push(this.props.draggingSubject);
}

mas no minuto em que os resultados do evento de arrastar começam a modificar adereços e renderização de componentes, o aviso acima começa a ser cuspido com frequência.

Eu não deveria estar fazendo isso?

O caso de uso é basicamente "visualizar" o item arrastado no momento no destino de soltar. O que está acima é uma prova de conceito - não conectado à loja Redux ainda, já que não tenho certeza se isso é mesmo válido.


Hm, parece que está tudo bem se eu mantiver minhas alterações locais para SubjectDisplayContent , mas os avisos começarão a acontecer se as alterações se estenderem para SubjectDisplay . Então, basicamente, se um dropTarget envia props para baixo que modificam um dropTarget diferente , react-dnd fica irritado. Isso é esperado e preciso repensar algumas coisas ou é um bug do dnd?

Estou enfrentando exatamente o mesmo problema. O que você pode fazer em algumas situações é criar um DragDropContext ao redor de cada arrastável aninhado. Mas isso não funciona assim que você deseja um DragLayer personalizado.

Recebi o mesmo erro, exceto que estou fazendo um dropTargets aninhado.
Depois de examinar a documentação, tentei usar

isOver (opções): Retorna verdadeiro se houver uma operação de arrastar em andamento e o ponteiro estiver pairando sobre o proprietário. Você pode, opcionalmente, passar {shallow: true} para verificar estritamente se apenas o proprietário está sendo pairado, ao contrário de um alvo aninhado.

(com a opção shallow is true) na função canDrop do dropTarget pai, e o problema foi embora. Eu acho que o mesmo poderia ser aplicado a alguns outros cenários.

@jchenjc Tentei fazer isso, mas não funcionou para mim. Para ser honesto, minha situação é extremamente complicada com visualização de arrastar aninhada + fonte de arrastar + destino de soltar que precisa funcionar em listas.

FWIW: Eu tenho fontes de arrastar aninhadas e uma camada de arrastar personalizada. Quando removo a camada de arrastar personalizada, a mensagem desaparece. Ao inspecionar o rastreamento de pilha, parece que o problema está aqui:

printWarning    @   warning.js?8a56:36
warning @   warning.js?8a56:60
getInternalInstanceReadyForUpdate   @   ReactUpdateQueue.js?6531:54
enqueueSetState @   ReactUpdateQueue.js?6531:200
ReactComponent.setState @   ReactComponent.js?702a:63
handleChange    @   DragLayer.js?1cbc:124 <--------------
handleChange    @   DragDropMonitor.js?0588:60

O código relevante está aqui . Vou ver por que o estado pode ser diferente no meu caso para acionar uma re-renderização ...

Com um dragsource + droptarget aninhado em um droptarget, recebo esse problema.

Parte da razão pela qual isso aconteceu é porque gaearon imaginou fazer a lista de arrastar e soltar tornando cada item da lista um destino de soltar, em vez de tornar o componente da lista um único destino de soltar que determina o que fazer com base na posição do foco de arrastar. A última maneira é como a maioria dos outros sistemas DnD que já vi fazem as coisas.

Caso isso ajude alguém: eu encontrei isso quando estava renderizando um componente que era uma fonte de arrastar em minha camada de arrastar personalizada porque era conveniente. Usei o componente arrastar fonte porque era a mesma entidade que eu estava tentando arrastar, então fazia sentido para mim manter o código "DRY" reutilizando-o. Eu não pensei sobre o fato de que ele tinha todo o código dragSource nele - olhando para trás, _é claro_ eu não gostaria de um código de arrastar como a coisa a ser renderizada na camada de arrastar personalizada.

Por fim, divido meu componente em uma versão "arrastável" que envolve o componente base e, em seguida, usei o componente base em minha camada de arrastar personalizada. Sem mais avisos, melhor código! 👍

@davidjoy woah, obrigado por compartilhar! Estou fazendo a mesma coisa, preciso tentar também!

@davidjoy Acabei de consertar o meu também. Sua sugestão aponta para não usar DragSource e tal para a camada personalizada. O que fiz foi simplesmente usar o componente simples sem DragSource na minha camada de arrastar personalizada e isso resolveu o problema.

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.

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