react-dnd / react-dnd

Drag and Drop for React

Home Page:http://react-dnd.github.io/react-dnd

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Preview Image only works once, on the first drag.

EOMedvis opened this issue · comments

First of all, I would like to state I'm completely new the React development, and there are probably some really basic things I'm missing that is causing the problem I will show below. Please bare with my newbie ignorance if that is the case.

I have a draggable object defined below, that I created following the examples on the React DnD site:

import type { CSSProperties, FC } from "react";
import { DragPreviewImage, useDrag } from "react-dnd";
import { DraggableTypes } from "./DraggableTypes";

export interface CardProps {
  cardData: CardType;
}

export const mainCardStyle: CSSProperties = {  
  border: '12px solid white',
  outline: '3px solid white',
  outlineOffset: '-20px',
  borderRadius: '25px',
  width: '65%',
  height: '100%',
  minWidth: '120px',
  minHeight: '320px',
  textAlign: 'center',
  color: 'white',
  backgroundImage: 'linear-gradient(to top, #396BE5, #ACA9E4)',  
  marginRight: '10px',
  marginBottom: '10px',
  cursor: 'move',
  float: 'left',
  boxShadow: '0px 5px 8px grey'
};

const innerDivStyle: CSSProperties = {margin: '10px'};
const imageDivStyle: CSSProperties = {marginTop: '40px',marginBottom: '20px'};
const titleDivStyle: CSSProperties = {marginBottom: '10px'};

function collectHandler(monitor: any) {
  return {
    isDragging: monitor.isDragging(),
    handlerId: monitor.getHandlerId(),
  };
}

export const DraggableCard: FC<CardProps> = function Card({ cardData }) {
  const [{isDragging}, drag, preview] = useDrag(
    function () 
    {
      return {
        type: DraggableTypes.Card,
        item: { cardData },
        collect: collectHandler,
        //end: (item, monitor) => { preview(null, { captureDraggingState: true });}, <== unsure about this.              
      };
    },
    [cardData]
  );

  const opacity = isDragging ? 0.4 : 1;
  
  return (    
    <>
      <DragPreviewImage connect={preview} src={cardData.image + ".png"} />
      <div ref={drag} style={{ ...mainCardStyle, opacity }}>
        <div style={innerDivStyle}>
          <div style={imageDivStyle}>
            <img src="placeHolder.png" alt="IconPlaceholder" /> 
          </div>
          <div style={titleDivStyle}>
            <strong>{cardData.title}</strong>
          </div>
          <div>            
            {cardData.description}
          </div>
        </div>        
      </div>
    </>
  );
};

It's working, for the most part. I can drag it into a drop target and have stuff happened as I expected. The only problem is that if I drag the object, and let go without dropping it into the drop target, the next time I drag it, the preview image no longer works. Instead i just get a transparent copy of the draggable object that moves with my cursor, instead of the assigned preview image, as if I never assigned the preview image at all (it works as if this line: <DragPreviewImage connect={preview} src={cardData.image + ".png"} />, was completely removed from the code).

The draggable object is dynamically created from an array of data. So I'm not sure if Im supposed to clear data first each time I drop. I've asked Chat GPT for some insights and it told me I have to clear the preview and gave me the line I liked with the "<==". That hasn't fixed the issue, though.

I know React has some strangeness where if the data doesn't change, things don't rerender sometimes. I'm not sure if this is the issue. Am I doing something wrong, or is there some limitation in React DnD I'm not aware of? Thank you for your time. :)

@EOMedvis Please use key property on <DragPreviewImage key={new Date().getTime()} /> this will ensure the rerender on every drag

Oh. Awesome. Thank you for the solution!

I'm running into a second somewhat related problem. I am using an image for the preview and would like to scale it, but DragPreviewImage doesn't accept a CSS Style property (e.g. <DragPreviewImage style={{...style props}}>). Is there a way to scale the preview image without just editing the raw image itself? Or is there a better/different solution than using DragPreviewImage for a preview?

Actually, I think I fixed the PreviewImg not being scaled. I can scale and store an image as a src before feeding it to the DragPreviewImage and it seems to work.