bokuweb/react-rnd

When the react-draggable is initialized, the value of transform is doubled

alyonakkk opened this issue · 19 comments

Overview of the problem

I'm using react-rnd version [10.3.5]

My browser is: Chrome, but I saw the same problem in Firefox too

I am sure this issue is not a duplicate? No, because I saw an issue with the same problem, but an author solved the problem himself

Description

When the react-draggable is initialized, position in transform translate is doubled, but when I click on the RND element, it accept correct position
I think problem with props position

Expected behavior

When click on the arrow then timelines accept correct position

Actual behavior

When click on the arrow then timelines don't accept correct position, only after click on them

The same happens with my project when running visual tests in a headless Firefox, our coordinates are exactly double of what they should be. Weirdly it doesn't happen when running the app itself.

if you enable scale,
you need lazy loading your component, because child rely on the componentDidMounut of parent

if you enable scale, you need lazy loading your component, because child rely on the componentDidMounut of parent

I am also facing this problem. Can you provide an example?

I have many pages under react-tabs. Tabs are set forceRenderTabPanel={true}. One page have componenet in RND. When this tab is not active RND are rendered double the value. When this tab is active RND is rendered corectly.
When i set forceRenderTabPanel={false} in react-tabs, RND is rendered always correct , irrespective of tab is active or not.

jcham commented

It seems like this is the same problem as #766 , when scale > 1 then the translate position is wrong.
It does have something to do with the rendering order, as I didn't run into this problem before but all of a sudden it is happening.

Has anyone found a good solution? Dividing by scale does fix it initially, but after re-rendering it is not needed, and how does one detect which case it is?

如果启用缩放,则需要延迟加载组件,因为子组件依赖于父组件的 componentDidMounut

我也面临这个问题。你能举个例子吗?

I think no. I found it during code review. you can try lazy load the child component

class component loading order is child mounted >> parent mounted. this component mounting depend on parent mounted. but parent component is not mounted

jcham commented

Hi @laozei6401 thanks for your help, I don't think I really understand what you mean about about lazy loading the component, how would that help? Could you provide an example?

The way I'm seeing it, the scale value behaves erratically, have not figured out quite what the right logic is.

https://codesandbox.io/s/react-rnd-initial-position-zs76x7

Workaround is to not render rnd initialy.
Create a state with const [loaded, setLoaded] = useState(false);
Render rnd as below
<div onMouseOver={() => setLoaded(true)}>{loaded && <Rnd />}</div>

vimlesh1975

Messy workaround but I can't think of another way and it worked, thanks @vimlesh1975 !

I noticed that I only ever see this problem when I loaded my component inside Suspense

I'm having this issue as well. is there's a way to delay the load of the component to solve this?
I need to display the component without waiting for a mouse over or any other user event.

@gadi-playstream-gg you could use the solution from @vimlesh1975 above with a timeout instead of the onClick event, eg:

const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    const timer = setTimeout(() => setLoaded(true), 500);
    return () => {
      clearTimeout(timer);
    };
  }, []);

return <div>{loaded && <Rnd />}</div>

My issue didn't come from scale, rather from something about the css / transformations of the parent element I had.

Regardless of the cause, it was easy to spot the issue when i had the parent taking the whole screen width/height but the offsetFromParent values were something like -37 on both top and left, causing an offset that wasn't supposed to be there.

I just continuously set the offset to 0,0 using the following code in the body of the react component:

const ref = useRef<Rnd>(null);
if (ref.current) ref.current.offsetFromParent = { top: 0, left: 0 };
ash-r1 commented

I met the same issue using Rnd inside the <dialog> HTML5 element with an "open" attribute.

I made a small hotfix.

import React, { useState, useEffect } from 'react';
import { Rnd } from 'react-rnd';

// hotfix based on https://github.com/bokuweb/react-rnd/issues/846
type Props = React.ComponentProps<typeof Rnd> & {
  isOpen: boolean;
};
export const StableRnd: React.FC<Props> = (props) => {
  const isOpen = props.isOpen;
  const [isStable, setIsStable] = useState(false);
  useEffect(() => {
    if(isOpen){
      const timer = setTimeout(() => setIsStable(true), 1);
      return () => {
        setIsStable(false);
        clearTimeout(timer);
      };
    }
  }, [isOpen]);

  return <>
    {isStable && <Rnd {...props} />}
  </>
};

Use like below:

<dialog open={isOpen}>
  <StableRnd isOpen={isOpen}>
</dialog>

+1, seeing the same in headless tests using jsdom.

I'm seeing this on the second render in headless tests only, printing the CSSStyleDeclaration shows correct transform properties on the first render, with subsequent renders having doubled values for x/y.

Browser always renders correctly with the exact values using a controlled component with position/size props.

Note, in my case in the tests there is no show/hide functionality, the rnd is always displayed, scale is the default of 1.