react-draggable icon indicating copy to clipboard operation
react-draggable copied to clipboard

Draggable shifts position after reload of page (persistent coordinates)

Open cjesper opened this issue 2 years ago • 4 comments

Hi, I am developing an application where users can create views consisting of draggable components. As i want the views to be persistent i store the x/y-coordinates of each component in a database. When a page (view) is rendered, i then fetch the coordinates and use these to populate the view (using the defaultPosition-prop)

This works great but i have an infuriating problem. The first time a view is refreshed after a new component is added to a view (and saved), the components will shift position down and to the right. I made a short video showcasing the problem:
https://streamable.com/h00fm8

As can be seen in the console - the coordinates used when rendering the view after the reload are identical to the ones that are saved, but for some reason the element moves!

Here is my draggable component:

return (
      <Draggable
        grid={[25, 25]} disabled={!props.editingEnabled} defaultPosition={{x: x, y: y}}  onStop={handleStop}>
        <div style={{position: "static"}} //have tried with absolute and fixed as well, didn't help
            <h1>Testing</h1>
        </div>
      </Draggable>
    )

handleStop:

  const handleStop = (event) => {
    let x = event.layerX;
    let y = event.layerY;
    console.log("Saving position of element");
    console.log("Saving X/Y-position " + x + ", " + y);
    setX(x);
    setY(y);
    props.handleMoveCallback(x, y, props.componentName)
  };

handleMoveCallback is in the parent of the element:

 handleMoveCallback = (x, y, componentName) => {
    this.updateComponent(x, y, componentName);
  };

updateComponent = (x, y, componentName) => {
    let existingPositions = this.state.componentPositions;
    if (existingCompNames.includes(componentName)) {
      let objIndex = existingPositions.findIndex((ep => ep.componentName === componentName));
      existingPositions[objIndex].x = x;
      existingPositions[objIndex].y = y;
      this.setState(
         { componentPositions: existingPositions }, this.saveView());
    }
  };

saveView just posts the array of component positions to the backing API where it's stored in the database. The components are then rendered inside of an absolute position div:

....
let components = this.state.componentPositions.map((c) =>
     <DraggableFunctionComponent id={c.componentName}  key={c.componentName}
                                 x={c.x} y={c.y}
                                  componentName={c.componentName} parentCallBack={this.handleMoveCallback}                      
     />
.....
<div style={{ position: "absolute" }}>   
             {components}   
</div>

Any help would be greatly appreciated

cjesper avatar Nov 10 '21 12:11 cjesper

@cjesper Hi, Did you solve the issue?

timeisgolden avatar Dec 15 '21 16:12 timeisgolden

I'm having this same issue, I believe.

I'm setting the x and y positions with defaultPosition. On first load, it works. On rerender (changing props and changing back) it no longer calculates the correct x and y position.

Tammerabi avatar Mar 29 '22 05:03 Tammerabi

when I remove "defaultPosition" it works fine

ohmyguigs avatar Jul 28 '22 02:07 ohmyguigs

Hi does anyone have a solution for this ? I have the same problem here

gokugen avatar Aug 12 '22 04:08 gokugen