React-dnd: Como depurar "Não é possível chamar o foco após a queda"?

Criado em 19 abr. 2016  ·  24Comentários  ·  Fonte: react-dnd/react-dnd

Oi,
um dos meus colegas de trabalho consegue interromper de alguma forma o estado do monitor e pensa que está pairando, embora o mouse esteja para cima e dá a ele:

screenshot 2016-04-19 16 34 56

Alguma ideia de onde começar a depurar? Não consigo reproduzir e ele vê uma vez por semana.
Estou usando o back-end de toque alternado para lidar com eventos do mouse também com alguns ajustes.

triage wontfix

Comentários muito úteis

Também estou tendo esse problema - minha situação é que o componente React é o destino de soltar e a fonte de arrastar. Quando tenho dois componentes, posso arrastar e soltar uma vez antes de gerar o erro acima. Quando tenho três, funciona sem erros. Presumo que tenha algo a ver com os vários contextos em um único componente.

Todos 24 comentários

Assim, investiguei o problema de JS e descobri que antes desse erro, havia um erro lançado de um retorno de chamada definido pelo usuário quando deveria ocorrer uma queda, o que poderia ter quebrado o estado do monitor / armazenamento.

Também estou tendo esse problema - minha situação é que o componente React é o destino de soltar e a fonte de arrastar. Quando tenho dois componentes, posso arrastar e soltar uma vez antes de gerar o erro acima. Quando tenho três, funciona sem erros. Presumo que tenha algo a ver com os vários contextos em um único componente.

Tive esse problema e encontrei uma solução alternativa para meu caso de uso específico ontem à noite.

Para o contexto, eu estava renderizando uma lista de DragSources, e se qualquer um deles solto em um DropTarget, eles seriam removidos da lista de DragSources e o DropTarget seria substituído por um componente que renderiza o conteúdo do DragSource.

Uma parte essencial desta funcionalidade de arrastar e soltar (é um componente para combinar 'categorias' com itens) era um recurso para adicionar itens de volta à lista DragSource, que iria apenas substituir o item colocado por um DragSource e adicioná-lo de volta aos DragSources Lista.

image

Agora, essa exceção só ocorria quando eu colocava itens em todas as categorias e removia pelo menos uma (não quando a lista não estava cheia e eu removia um e o adicionava novamente). Então cheguei à conclusão de que a lista DragSources nunca poderia ter zero filhos para que isso ocorresse (possivelmente devido ao desaparecimento do elemento contêiner, mas não tive tempo suficiente para testar isso). Para atenuar isso, em vez de remover itens da lista DragSources na colocação, apenas defini seu estilo para display: none

É difícil de explicar, mas espero que ajude.

Estou experimentando o mesmo efeito que @PendragonDevelopment. Minha lista começa com um item, adiciona um segundo a ela e pode ser reorganizada. Você só pode reorganizar os dois itens uma vez antes de começar a ver os erros de Javascript e nunca mais poderá reorganizá-los.

Eu tenho esse problema também
Não sei por que, mas após o primeiro rearranjo, vejo esses erros

Eu tenho o mesmo erro aqui.

Depois de algumas comparações entre o exemplo de demonstração e o meu, descobri que, quando faço um loop dos componentes, uso a chave do array para definir o componente tanto a chave quanto o índice e na demonstração eles definem apenas o índice Sortable / Simple / Container.js e a chave é fixa.

Fiz e funcionou!

A chave deve ter um valor fixo porque se não for, a referência ao componente será perdida após a reordenação da matriz.

Quando você tiver um componente criando e anexando DnD dinamicamente, você deve usar alguma biblioteca ou talvez Date.now() fará isso para gerar chaves exclusivas para cada componente.

{this.state.rows.map(function(row, key) {
  return (<RowComponent key={row.id} index={key} id={row.id} moveRow={that.moveRow} />);
})}

row.id é único para cada componente

Não entendo por que funciona, mas usar meu model.id em vez de uma chave aleatória gerada por node-uuid's v4 consertou. Pelo menos não estou recebendo mais erros.

Consertar a chave não resolveu meu problema.
Este era o meu código

           <ContentPatch>
             {tasks.loading 
              ? <div>...loading </div>
              : this.state.containers.map((item, i) => {
                  return (
                    <TaskStage
                      key={item.id}
                      item={item}
                      tasklist={tasks.tasks}
                      onDropped={this.handleDropped}
                      onBeginningDrag={this.onBeginningDrag}
                    />
                  );
                })}
          </ContentPatch>

Após cada ação eliminada, mapeava todos os itens e recebia o mesmo erro.
E eu mudei minha condição para

...
{tasks.loading && tasks.tasks.length===0
 ? <div>...loading </div>
...

e está resolvido. Acho que, mais uma vez, a montagem é a razão desse erro.

Eu me deparei com esse mesmo erro.

Meu caso de uso foi:

  • Mesmo DragSource e DragTarget componente
  • Em queda, eu queria navegar para uma rota

Acontece que endDrag ( DragSource method) dispara após drop ( DropTarget method). Eu estava lidando com a navegação de rota dentro de drop que estava quebrando o estado do monitor.

Movida essa lógica para endDrag para consertar. A refatoração envolvia verificar se a eliminação foi concluída com monitor.didDrop() , mas não foi tão ruim.

Eu tenho esse problema também. Meu caso é que o componente é o destino de soltar e a fonte de arrastar. Tentei usar o método endDrag e tentei usar back-end corrigido (https://gist.github.com/nickpresta/eb5cce69d650db4c2795). Isso não resolveu esse problema.

meu componente:

@DropTarget<HeadColOwnProps>(TaskDndTypes.headCol, headColTargetSpec, headColTargetCollector)
@DragSource<HeadColOwnProps>(TaskDndTypes.headCol, headColSourceSpec, headColSourceCollector)
class HeadColComponent extends React.Component<any, void> {
    render() {
        const props = this.props;
        return this.props.dndConnectDropTarget(
            this.props.dndConnectDragPreview(
                <div>
                    <div className={block('panels-task__drag')({start: props.dndIsDragging})}>
                        <SortingIcon
                            label={props.label}
                            arrowIsVisible={props.sortingIsPossible}
                            direction={props.sortingDirection}
                            clickHandler={props.sortingHandler}
                        />
                        {this.props.dndConnectDragSource(
                            <span className="panels-task__drag-control">
                                <SVGIcon width={10} height={10} url={'#icon-drag-and-drop-cell'} />
                            </span>
                        )}
                    </div>
                </div>
            )
        );
    }
}

Exemplo de uso:

const renderHeadCellId = (): JSX.Element => {
        return (
            <TaskCellHead key="key-head-col-id" modifications={{ number: true }}>
                <HeadColComponent
                    label="#"
                    key="key-dnd-head-col-id"
                    taskColType={TaskCols.id}
                    sortingIsPossible={false}
                    taskColsOrder={taskStore.orderCols}
                    updateDragProcess={(dp: TaskColDragProcess | null) => taskStore.updateDragProcess(dp)}
                    updateOrderCols={(order: TaskCols[]) => taskStore.updateOrderCols(order)}
                    dragProcess={taskStore.dragProcess}
                />
            </TaskCellHead>
        );
    };

Configurações do decorador:

const headColSourceSpec: DragSourceSpec<HeadColOwnProps> = {
    beginDrag(props: HeadColOwnProps): DraggedItem {
        return { sourceColType: props.taskColType };
    },
    canDrag(props: HeadColOwnProps): boolean {
        return props.taskColsOrder.length > 1;
    },
    endDrag(props: HeadColOwnProps, monitor: DragSourceMonitor): void {
        console.debug('endDrag');
        if (!monitor.didDrop()) {
            return;
        }
        console.debug('endDrag finish');
        props.updateOrderCols((monitor.getDropResult() as DroppedResult).newOrderCols);
    }
};

const headColTargetSpec: DropTargetSpec<HeadColOwnProps> = {
    drop(props: HeadColOwnProps, monitor: DropTargetMonitor): DroppedResult {
        console.debug('drop');
        return {
            newOrderCols: getNewOrder((monitor.getItem() as DraggedItem).sourceColType, props.taskColsOrder, props.dragProcess)
        };
    },
    hover(props: HeadColOwnProps, monitor: DropTargetMonitor, component: HeadColComponent): Object | void {
        if (!monitor.canDrop()) {
            return;
        }
        // ...
        props.updateDragProcess(currentDragProcess);
    },
    canDrop(props: HeadColOwnProps, monitor: DropTargetMonitor): boolean {
        return props.taskColType !== (monitor.getItem() as DraggedItem).sourceColType;
    }
};

const headColSourceCollector = (connect: DragSourceConnector, monitor: DragSourceMonitor) => ({
    dndConnectDragSource: connect.dragSource(),
    dndConnectDragPreview: connect.dragPreview(),
    dndIsDragging: monitor.isDragging()
});

const headColTargetCollector = (connect: DropTargetConnector, monitor: DropTargetMonitor) => {
    return {
        dndConnectDropTarget: connect.dropTarget(),
        dndIsOverCurrent: monitor.isOver({ shallow: true })
    };
};

Notei que após o rearranjo endDrag não é chamado, mas drop é chamado. Essas linhas nunca são executadas:

endDrag(props: HeadColOwnProps, monitor: DragSourceMonitor): void {
        console.debug('endDrag');
        if (!monitor.didDrop()) {
            return;
        }
        console.debug('endDrag finish');
        props.updateOrderCols((monitor.getDropResult() as DroppedResult).newOrderCols);
    }

O que estou fazendo errado? Alguma ideia?

Substituí HTML5Backend por Touch Backend (https://github.com/yahoo/react-dnd-touch-backend). Funciona para mim.

Para mim, estava recebendo esse erro apenas por ter pontos de interrupção definidos no retorno de chamada no drop. O interessante é que ele iria falhar mesmo depois que todos os pontos de interrupção continuassem e o navegador não estivesse pausado. Assim que retirei os breakpoints, o erro foi embora.

Estou tendo o mesmo problema. Substituído este pacote por react-dnd-touch-backend, mas isso realmente não ajuda a resolver o problema. Eu prefiro executar o html5. Tentei definir chaves em todos os elementos que estão sendo impressos por um iterador.

Eu estava recebendo o mesmo erro. Eu estava reaplicando um HOC nos componentes arrastáveis ​​em cada render, para que fossem sempre diferentes, o que confundia a reação.

@hakunin você resolveu isso (eu também só recebo esse erro depois que outro erro de tempo de execução ocorreu).

Desde então, refatorei todo o código DnD que tenho e ainda consigo quando começo a arrastar. Agora que movi todo o código para um único arquivo util e o tornei configurável, posso finalmente encontrar o motivo pelo qual isso acontece em algum momento. Vou postar sobre isso aqui quando eu fizer isso. (Estou usando o TouchBackend na configuração do mouse, aliás)

Obrigado pela resposta. Eu só recebo esse erro depois que algum outro erro ocorre enquanto arrasto - ponto em que parece irrecuperável. isso é o mesmo para você?

O meu reclama toda vez que começo a arrastar.

Meu caso foi que o componente em endDrag (adereços, monitor, componente) ficou indefinido depois que o item foi descartado. Então, isso estava causando meu erro original, que levou ao fluxo do console de mensagens "Não é possível chamar o foco após a queda".

Consegui resolver esse problema graças a este comentário: https://github.com/react-dnd/react-dnd/issues/431#issuecomment -317219509

Eu conheci isso quando eu causei outro erro não bloqueado antes. não há esse erro quando não havia outros erros.

No meu caso aconteceu quando no endDrag eu chamo alguma ação / função que causa erro. Então, o erro basicamente não detectado fez o dnd travar. você pode usar try catch ao chamar alguma função / ação no bloco endDrag.
endDrag: (props, monitor) => { try { handleEndDrag(); } catch(errror) { console.error(error)} }

Uma instrução do depurador dentro da função onDrop também foi a fonte do erro para mim. Removê-lo faz com que o erro desapareça, mas estou tendo dificuldade em depurar sem ele.

Alguma ideia de por que o depurador está provocando esse erro?

Não tenho certeza se é de algum interesse, mas estou executando um aplicativo Electron.

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