UNPKG

@atlaskit/pragmatic-drag-and-drop-docs

Version:

This package holds the documentation for Pragmatic drag and drop in one place. It is not intended to be consumed directly by consumers. The package is used by other tools for sharing examples

139 lines (108 loc) 3.71 kB
## Attaching behavior We advise that you attach drag and drop behaviour to elements using [the `useEffect` hook](https://reactjs.org/docs/hooks-effect.html). ```tsx // card.tsx import {draggable, dropTargetForElements} from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; export default function Card({ item }: { item: Item }) { const ref = useRef<HTMLDivElement | null>(null); const itemId = item.itemId; const [state, setState] = useState<DraggableState>('idle'); useEffect(() => { const cleanup = combine( draggable({ element: ref.current, getInitialData: () => ({ type: 'card', itemId: itemId }), }), dropTargetForElements({ element: ref.current, canDrop: args => args.source.data.type === 'card', }), ); return cleanup; }, [itemId]); return ( <div ref={ref}> item id: {item.itemId}</span> </div> ); }; ``` It is fine if your `draggable` or `dropTargetForElements` effect is cleaned up and re-created, even during a drag. For both of `draggable` and _drop targets_, the `element` is used as the _key_ for the entity. For more information, see [reconciliation](/components/pragmatic-drag-and-drop/core-package/reconciliation); ## Monitors Using effects is also a nice way to manage the lifecyle of monitors: ```tsx export function App() { useEffect(() => { // this is nice as the monitor will be cleaned up when <App /> is unmounted const cleanup = monitorForExternal({ onDragStart: () => console.log('A file is dragging!'); }); return cleanup; }, []); return <Example>; }; ``` ## Deferred loading React lazy loading is based on components ([more details](https://reactjs.org/docs/code-splitting.html)). You can use this component pattern with Pragmatic drag and drop: ```tsx import { Suspense, lazy } from 'react'; // importing our `card.tsx` file from above const LazyCard = lazy(() => ('./card.tsx')); function App() { return <Suspense fallback="loading..."><LazyCard></Suspense> } ``` Since this framework is not tied to `react`, you can also attach drag and drop behavior at some point after a component has already been rendered: ```tsx function Card({ item }: { item: Item }) { const ref = useRef<HTMLDivElement | null>(null); const itemId = item.itemId; useEffect(() => { const controller = new AbortController(); // Look! We are attaching behaviour after the component has rendered! // Note: Atlassian's, please use http://go/react-async rather than this promise based approach (async () => { const modules = await Promise.all([ await import('@atlaskit/pragmatic-drag-and-drop/element/adapter'), await import('@atlaskit/pragmatic-drag-and-drop/combine'), ]); if (controller.signal.aborted) { return; } const [{ draggable, dropTargetForElements }, { combine }] = modules; if (!ref.current) { return; } const cleanup = combine( draggable({ element: ref.current, getInitialData: () => ({ type: 'card', itemId: itemId }), }), dropTargetForElements({ element: ref.current, canDrop: args => args.source.data.type === 'card', getData: () => ({ type: 'card', itemId: itemId }), }), ); controller.signal.addEventListener('abort', cleanup, { once: true }); })(); return () => { controller.abort(); }; }, [itemId]); return ( <div ref={ref}> item id: {item.itemId}</span> </div> ); }; ``` For more details, see our [deferred loading guide](/components/pragmatic-drag-and-drop/core-package/recipes/deferred-loading).