atlassian / react-beautiful-dnd

Beautiful and accessible drag and drop for lists with React
https://react-beautiful-dnd.netlify.app
Other
33.32k stars 2.55k forks source link

Is this support in React 18? #2399

Closed fahadashiq12 closed 2 years ago

fahadashiq12 commented 2 years ago

My console screen has following message:

react-beautiful-dndDroppable setup issue [droppableId: "todo"]:

DroppableProvided > placeholder could not be found.Please be sure to add the {provided.placeholder}

React Node as a child of your Droppable.More information: https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/api/droppable.md👷‍

This is a development only message. It will be removed in production builds.

alumbo commented 2 years ago

I'm using it with React 18 without troubles.

fahadashiq12 commented 2 years ago

I'm using it with React 18 without troubles.

I am reading some articles that react-dnd-beautiful has become obsolete after react 16 version, well react-dnd can still be use in react 18?

I am have installed it using -peer-legacy command while installing through npm which is reccommended for legacy support feature in latest version of React - any other alternative to it?

gavinorland commented 2 years ago

It works with React 18 but not inside the StrictMode wrapper.

Himanshu9271 commented 2 years ago

It works with React 18 but not inside the StrictMode wrapper.

Thanks, removing StrictMode Wrapper worked for me. I was getting Unable to find draggable with id: 2 errors. I am not sure what was causing this. But thanks again for the help.

alexcloudstar commented 2 years ago

It works with React 18 but not inside the StrictMode wrapper.

Same issue as above. It was not finding the draggable with id. After removing the StrictMode wrapper it working perfectly. Thanks! (I'm using react 18 as well)

einarq commented 2 years ago

Is there an issue registered for not working within Strict Mode? Probably related to the double firing of useEffect.

fahadashiq12 commented 2 years ago

Can someone explain what is #strictmode?

einarq commented 2 years ago

"StrictMode is a tool for highlighting potential problems in an application."

https://reactjs.org/docs/strict-mode.html https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#updates-to-strict-mode

On Thu, May 19, 2022 at 3:03 PM Fahad Ashiq ⚡ @.***> wrote:

Can someone explained what is #StrictMode?

— Reply to this email directly, view it on GitHub https://github.com/atlassian/react-beautiful-dnd/issues/2399#issuecomment-1131662225, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABT6D2ADCCX3GZTIM4YPLDVKY32TANCNFSM5UH3T6AA . You are receiving this because you commented.Message ID: @.***>

Patil-Mayur commented 2 years ago

i am getting draggable id issue without using it in strict mode

https://codesandbox.io/s/staging-field-ej6ghv?file=/src/App.js

GiovanniACamacho commented 2 years ago

Just be aware that this new bug with React 18 has to do with concurrent rendering and how 'react-beautiful-dnd' registers their droppables inside the hook. The library is doing it inside a useLayoutEffect with a dependency array, so it will fire on the first componentDidMount, but not afterwards when the component gets remounted, which is how React 18 behaves in StrictMode.

GiovanniACamacho commented 2 years ago

One way I found to fix the issue with react-beautiful-dnd and React 18 in StrictMode was to render the Droppable elements after an animation frame... something like this:

const DropComponent = () => {

  const [ enabled, setEnabled ] = React.useState(false);

  React.useEffect(() => {
    const animation = requestAnimationFrame(() => setEnabled(true));

    return () => {
       cancelAnimationFrame(animation);
       setEnabled(false);
    };
  }, []);

  if (!enabled) {
      return null;
  }

  return (
    <Droppable droppableId={...}>
       { .... }
    </Droppable>
  );
}

In my case, it seemed to have fixed the timing issue when register.clean was getting called after the Droppable elements were registered.

Meligy commented 2 years ago

One way I found to fix the issue with react-beautiful-dnd and React 18 in StrictMode was to render the Droppable elements after an animation frame... something like this:

Thanks a lot. This seems to work for me.

If anyone needs a TypeScript version:

import { useEffect, useState } from "react";
import { Droppable, DroppableProps } from "react-beautiful-dnd";

export const StrictModeDroppable = ({ children, ...props }: DroppableProps) => {
  const [enabled, setEnabled] = useState(false);

  useEffect(() => {
    const animation = requestAnimationFrame(() => setEnabled(true));

    return () => {
      cancelAnimationFrame(animation);
      setEnabled(false);
    };
  }, []);

  if (!enabled) {
    return null;
  }

  return <Droppable {...props}>{children}</Droppable>;
};
dharmikshahitworld commented 2 years ago

Thanks guys, I was also face the same issue then, I found this page and removed 'stricktMode' and now it's working fine for me. You make my day.

Xhale1 commented 2 years ago

Hello! I released a fork of this project which natively supports React 18 and strict mode, called @hello-pangea/dnd

  1. npm install @hello-pangea/dnd
  2. Replace all imports of react-beautiful-dnd with @hello-pangea/dnd
  3. Good to go
chaithracheth commented 2 years ago

It works with React 18 but not inside the StrictMode wrapper.

Same issue as above. It was not finding the draggable with id. After removing the StrictMode wrapper it working perfectly. Thanks! (I'm using react 18 as well)

yes I ts worked for me, thank u so much

danieldelcore commented 2 years ago

Hey folks, I've updated the peerdep in the latest version.

It works with React 18 but https://github.com/atlassian/react-beautiful-dnd/issues/2350 inside the StrictMode wrapper.

This is still correct

danieldelcore commented 2 years ago

Will close this issue for now, let's continue the discussion about strict mode support here: https://github.com/atlassian/react-beautiful-dnd/issues/2350

semihraifgurel commented 2 years ago

It works with React 18 but not inside the StrictMode wrapper.

Thank you very much @gavinorland, I've been going crazy for two or three days.

cvsonar18 commented 1 year ago

Thanks a lot its works for me without turning off StrictMode

thislekan commented 1 year ago

One way I found to fix the issue with react-beautiful-dnd and React 18 in StrictMode was to render the Droppable elements after an animation frame... something like this:

Thanks a lot. This seems to work for me.

If anyone needs a TypeScript version:

import { useEffect, useState } from "react";
import { Droppable, DroppableProps } from "react-beautiful-dnd";

export const StrictModeDroppable = ({ children, ...props }: DroppableProps) => {
  const [enabled, setEnabled] = useState(false);

  useEffect(() => {
    const animation = requestAnimationFrame(() => setEnabled(true));

    return () => {
      cancelAnimationFrame(animation);
      setEnabled(false);
    };
  }, []);

  if (!enabled) {
    return null;
  }

  return <Droppable {...props}>{children}</Droppable>;
};

Works perfect!!! Thank you all!

florin-holhos commented 1 year ago

For React 18, the trick is just to make sure that component it's mounted when rendering 'Droppable'.

    const [isMounted, setIsMounted] = useState(false);

    useEffect(() => {
        setIsMounted(true);
    }, []);

    return isMounted ? <Droppable {...props}>{children}</Droppable> : null;

You don't need to create a new component just for this...

maariyadiminsky commented 1 year ago

@florin-holhos's answer worked for awhile until I added more code and had more than one useEffect running in my component. This caused the same issue to return.

This completely fixed the issue. Here is a hook version of that:

import { useEffect, useState } from 'react';

export const useDragAndDropWithStrictMode = () => {
  const [isDragAndDropEnabled, setIsDragAndDropEnabled] = useState(false);

  useEffect(() => {
    const animation = requestAnimationFrame(() => setIsDragAndDropEnabled(true));

    return () => {
      cancelAnimationFrame(animation);
      setIsDragAndDropEnabled(false);
    };
  }, []);

  return { isDragAndDropEnabled };
};

Then use like so:


return (isDragAndDropEnabled ? <Droppable ...>...</Droppable> : null);
DawidBugajski commented 1 year ago

I have bunch of problems in typescript, using this code

Bez tytułu

GiovanniACamacho commented 1 year ago

@DawidBugajski ,

I'd imagine it is because of the JSX code. Probably need to change the file extension to .tsx instead of .ts

benbonnet commented 1 year ago

worked great!

that is, for reasons i could not resolve, nested lists briefly disappears on state update, so the whole list kinda jumps up & down at that moment; feels glitchy

patilniranjan7 commented 1 year ago

It will work with React 18 with 2 ways

1) remove strictmode 2) dont use createRoot use ReactDOM.render

fahadashiq12 commented 1 year ago

It will work with React 18 with 2 ways

1) remove strictmode

2) dont use createRoot use ReactDOM.render

Thankyou for answering ✅

lxiiiixi commented 1 year ago

Thanks soooo much! The best solution in my mind!!

For React 18, the trick is just to make sure that component it's mounted when rendering 'Droppable'.

    const [isMounted, setIsMounted] = useState(false);

    useEffect(() => {
        setIsMounted(true);
    }, []);

    return isMounted ? <Droppable {...props}>{children}</Droppable> : null;

You don't need to create a new component just for this...

ddumst commented 1 year ago

Until today the @Meligy answer saved my life (well some hours of my life)

FathyMuhamed commented 1 year ago

One way I found to fix the issue with react-beautiful-dnd and React 18 in StrictMode was to render the Droppable elements after an animation frame... something like this:

Thanks a lot. This seems to work for me.

If anyone needs a TypeScript version:

import { useEffect, useState } from "react";
import { Droppable, DroppableProps } from "react-beautiful-dnd";

export const StrictModeDroppable = ({ children, ...props }: DroppableProps) => {
  const [enabled, setEnabled] = useState(false);

  useEffect(() => {
    const animation = requestAnimationFrame(() => setEnabled(true));

    return () => {
      cancelAnimationFrame(animation);
      setEnabled(false);
    };
  }, []);

  if (!enabled) {
    return null;
  }

  return <Droppable {...props}>{children}</Droppable>;
};

Thank you very much

iampava commented 1 year ago

I was using the "hack" with an animation frame described above https://github.com/atlassian/react-beautiful-dnd/issues/2399#issuecomment-1175638194 but found a problem in my app.

The initial render is null as expected by that code, which leads to a flicker:

  1. first time nothing is rendered
  2. after the useEffect & animationFrame runs I render the children

This was problematic for my app and the user experience so I ended up modifying the code to ONLY have this "hack" in development. We don't need it in productions since the <React.StrictMode> has no effect there:

NOTE: I'm using Vite that's why I have the import.meta special object. A similar approach using "native" props would be process.env.NODE_ENV

import { useEffect, useState } from "react";
import { Droppable, DroppableProps } from "react-beautiful-dnd";

export const StrictModeDroppable = ({ children, ...props }: DroppableProps) => {
  const [enabled, setEnabled] = useState(import.meta.env.MODE === "production");

  useEffect(() => {
    const animation = requestAnimationFrame(() => setEnabled(true));

    return () => {
      cancelAnimationFrame(animation);
      setEnabled(false);
    };
  }, []);

  if (!enabled) {
    return null;
  }

  return <Droppable {...props}>{children}</Droppable>;
};
Ihatetomatoes commented 9 months ago

One way I found to fix the issue with react-beautiful-dnd and React 18 in StrictMode was to render the Droppable elements after an animation frame... something like this:

Thanks a lot. This seems to work for me.

If anyone needs a TypeScript version:

import { useEffect, useState } from "react";
import { Droppable, DroppableProps } from "react-beautiful-dnd";

export const StrictModeDroppable = ({ children, ...props }: DroppableProps) => {
  const [enabled, setEnabled] = useState(false);

  useEffect(() => {
    const animation = requestAnimationFrame(() => setEnabled(true));

    return () => {
      cancelAnimationFrame(animation);
      setEnabled(false);
    };
  }, []);

  if (!enabled) {
    return null;
  }

  return <Droppable {...props}>{children}</Droppable>;
};

This worked like a charm. If anyone needs unit tests, this worked for me:

import { renderWithProviders } from "@/utils/testUtils";
import { act, screen } from "@testing-library/react";
import { DragDropContext } from "react-beautiful-dnd";
import { StrictModeDroppable } from "./StrictModeDroppable";

describe("StrictModeDroppable", () => {
  let originalRequestAnimationFrame: (callback: FrameRequestCallback) => number;

  // Mocking requestAnimationFrame
  beforeAll(() => {
    originalRequestAnimationFrame = window.requestAnimationFrame;

    jest.spyOn(window, "requestAnimationFrame").mockImplementation((cb) => {
      cb(0);
      return 0;
    });
  });

  afterAll(() => {
    // Restore the original requestAnimationFrame function
    window.requestAnimationFrame = originalRequestAnimationFrame;
  });

  it("renders Droppable when enabled", () => {
    act(() => {
      renderWithProviders(
        <DragDropContext onDragEnd={jest.fn()}>
          <StrictModeDroppable droppableId={"items"}>
            {(provided) => (
              <div
                data-testid="child-component"
                ref={provided.innerRef}
                {...provided.droppableProps}
              >
                Child Component
              </div>
            )}
          </StrictModeDroppable>
        </DragDropContext>
      );
    });

    const droppableComponent = screen.getByTestId("child-component");
    expect(droppableComponent).toBeInTheDocument();
  });

  it("does not render Droppable when not enabled", () => {
    jest.useFakeTimers();

    act(() => {
      renderWithProviders(
        <StrictModeDroppable
          droppableId={"items"}
          data-testid="strict-mode-droppable"
        >
          {(provided) => <div>Child Component</div>}
        </StrictModeDroppable>
      );

      // Fast-forward time to trigger useEffect
      jest.runAllTimers();
    });

    const droppableComponent = screen.queryByTestId("strict-mode-droppable");
    expect(droppableComponent).toBeNull();
  });
});
ManojKarger commented 8 months ago

It works with React 18 but not inside the StrictMode wrapper.

It works with React 18

patilniranjan7 commented 8 months ago

Dont Revome strict mode. just use createRoot, in index.js. I have achieved multiple drag-drop and some advance functionality with this. Removing strict mode was a bad idea just change the rendering way. we will use old way. This will not effect performance.