React-dnd: HTML5Backend para de arrastar quando há elementos no DOM que aparecem/desaparecem no evento de arrastar: CHROME

Criado em 1 abr. 2020  ·  3Comentários  ·  Fonte: react-dnd/react-dnd

Descreva o erro
Temos um problema sério com o html5backend. Precisamos gerar algumas lacunas para orientar o usuário onde soltar o elemento arrastado, queremos que essas lacunas sejam visíveis apenas enquanto o elemento estiver sendo arrastado.
No firefox funciona perfeitamente, mas no chrome, os cartões iniciam o evento stop arrastando imediatamente após o evento start arrastando.

Reprodução
https://codesandbox.io/s/react-dnd-sortable-holes-bq2oe
Cada cartão é arrastável e quando o usuário começa a arrastar aparecem lacunas laranja.
image

image

No firefox funciona muito bem, mas no chrome o evento stop é lançado imediatamente após o evento start.

Como você pode ver no console:
image

  • SO: [por exemplo, iOS]
  • Navegador: Bug no Chrome versão 80.0.3987.162, funciona perfeitamente no firefox 74.0 (64 bits)

Qualquer ajuda será muito apreciada, realmente precisamos dessa funcionalidade.

Comentários muito úteis

Nossa equipe melhorou a solução de estado criando um gancho personalizado para o provedor de arrastar e soltar, em qualquer caso que algum de vocês enfrente esse problema, aqui está uma solução enquanto o bug é resolvido.

https://codesandbox.io/s/react-dnd-sortable-gaps-custom-9tl13

A parte principal consiste em definir um Contexto e um Provedor para armazenar o status de arrastamento.

const DndContext = React.createContext([{}, () => {}]);

const DndCustomProvider = props => {
  const [state, setState] = useState({ dragging: false });

  return (
    <DndProvider backend={props.backend}>
      <DndContext.Provider value={[state, setState]}>
        {props.children}
      </DndContext.Provider>
    </DndProvider>
  );
};

Em segundo lugar, usando setTimeout na função drag begin, o end dispatch é evitado.

  const [context, setContext] = useContext(DndContext);

  const [collected, dragRef] = useDrag({
    ...,
    begin: monitor => {
      setTimeout(() => {
        setContext(() => ({ dragging: true }));
      }, 0);

      if (begin) {
        begin(monitor);
      }
    },
    end: (item, monitor) => {
      setContext(() => ({ dragging: false }));

      if (end) {
        end(item, monitor);
      }
    },
    ...
  });

  return [
    {
      ...collected,
      isDragging: context.dragging
    },
    dragRef
  ];

E, finalmente, o valor coletado isDragging é substituído pelo valor de contexto.

Todos 3 comentários

Encontrei uma solução, lendo bastante, para esse problema, definindo um timeout e uma variável de estado que passo por componentes, não gosto muito, pois nesses casos simples é fácil de fazer, mas em complexos casos eu deveria usar contexto ou algo semelhante para fazer tudo funcionar.
https://codesandbox.io/s/react-dnd-sortable-holes-vxeus

Espero que você possa me guiar por uma solução melhor, gostaria de usar o isDragging da biblioteca em vez desta solução alternativa.

Nossa equipe melhorou a solução de estado criando um gancho personalizado para o provedor de arrastar e soltar, em qualquer caso que algum de vocês enfrente esse problema, aqui está uma solução enquanto o bug é resolvido.

https://codesandbox.io/s/react-dnd-sortable-gaps-custom-9tl13

A parte principal consiste em definir um Contexto e um Provedor para armazenar o status de arrastamento.

const DndContext = React.createContext([{}, () => {}]);

const DndCustomProvider = props => {
  const [state, setState] = useState({ dragging: false });

  return (
    <DndProvider backend={props.backend}>
      <DndContext.Provider value={[state, setState]}>
        {props.children}
      </DndContext.Provider>
    </DndProvider>
  );
};

Em segundo lugar, usando setTimeout na função drag begin, o end dispatch é evitado.

  const [context, setContext] = useContext(DndContext);

  const [collected, dragRef] = useDrag({
    ...,
    begin: monitor => {
      setTimeout(() => {
        setContext(() => ({ dragging: true }));
      }, 0);

      if (begin) {
        begin(monitor);
      }
    },
    end: (item, monitor) => {
      setContext(() => ({ dragging: false }));

      if (end) {
        end(item, monitor);
      }
    },
    ...
  });

  return [
    {
      ...collected,
      isDragging: context.dragging
    },
    dragRef
  ];

E, finalmente, o valor coletado isDragging é substituído pelo valor de contexto.

Alguém tem uma solução ou uma ideia para um patch para este problema que não envolva tal solução alternativa?

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

Questões relacionadas

redochka picture redochka  ·  3Comentários

greggigon picture greggigon  ·  4Comentários

bebbi picture bebbi  ·  3Comentários

croraf picture croraf  ·  3Comentários

gocreating picture gocreating  ·  4Comentários