React-dnd: HTML5Backend๋Š” ๋“œ๋ž˜๊ทธ ์ด๋ฒคํŠธ์—์„œ ํ‘œ์‹œ/์‚ฌ๋ผ์ง€๋Š” DOM ์š”์†Œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋“œ๋ž˜๊ทธ๋ฅผ ์ค‘์ง€ํ•ฉ๋‹ˆ๋‹ค. CHROME

์— ๋งŒ๋“  2020๋…„ 04์›” 01์ผ  ยท  3์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: react-dnd/react-dnd

๋ฒ„๊ทธ ์„ค๋ช…
html5backend์— ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋“œ๋ž˜๊ทธํ•œ ์š”์†Œ๋ฅผ ๋“œ๋กญํ•  ์œ„์น˜๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•ˆ๋‚ดํ•˜๊ธฐ ์œ„ํ•ด ์•ฝ๊ฐ„์˜ ๊ฐ„๊ฒฉ์„ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฐ„๊ฒฉ์€ ์š”์†Œ๊ฐ€ ๋“œ๋ž˜๊ทธ๋˜๋Š” ๋™์•ˆ์—๋งŒ ํ‘œ์‹œ๋˜๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค.
ํŒŒ์ด์–ด ํญ์Šค์—์„œ๋Š” ์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ•˜์ง€๋งŒ ํฌ๋กฌ์—์„œ๋Š” ์นด๋“œ๊ฐ€ ๋“œ๋ž˜๊ทธ ์‹œ์ž‘ ์ด๋ฒคํŠธ ์งํ›„์— ๋“œ๋ž˜๊ทธ ์ค‘์ง€ ์ด๋ฒคํŠธ๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์ƒ์‹
https://codesandbox.io/s/react-dnd-sortable-holes-bq2oe
๊ฐ ์นด๋“œ๋Š” ๋Œ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์‚ฌ์šฉ์ž๊ฐ€ ๋Œ๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด ์ฃผํ™ฉ์ƒ‰ ๊ฐ„๊ฒฉ์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.
image

image

ํŒŒ์ด์–ด ํญ์Šค์—์„œ๋Š” ๋งค๋ ฅ์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜์ง€๋งŒ ํฌ๋กฌ์—์„œ๋Š” ์‹œ์ž‘ ์ด๋ฒคํŠธ ์งํ›„์— ์ค‘์ง€ ์ด๋ฒคํŠธ๊ฐ€ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

์ฝ˜์†”์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด :
image

  • OS: [์˜ˆ: iOS]
  • ๋ธŒ๋ผ์šฐ์ €: Chrome ๋ฒ„์ „ 80.0.3987.162์˜ ๋ฒ„๊ทธ, firefox 74.0(64๋น„ํŠธ)์—์„œ ์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™

๋„์›€์„ ์ฃผ์‹œ๋ฉด ์ •๋ง ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์ด ์ •๋ง ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์šฐ๋ฆฌ ํŒ€์€ ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ ๊ณต๊ธ‰์ž๋ฅผ ์œ„ํ•œ ์‚ฌ์šฉ์ž ์ง€์ • ํ›„ํฌ๋ฅผ ๋งŒ๋“œ๋Š” ์ƒํƒœ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๊ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ์— ์ง๋ฉดํ•œ ์‚ฌ๋žŒ์ด ์žˆ์„ ๊ฒฝ์šฐ ์—ฌ๊ธฐ์— ๋ฒ„๊ทธ๊ฐ€ ํ•ด๊ฒฐ๋˜๋Š” ๋™์•ˆ ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

https://codesandbox.io/s/react-dnd-sortable-gaps-custom-9tl13

์ฃผ์š” ๋ถ€๋ถ„์€ ๋“œ๋ž˜๊ทธ ์ƒํƒœ๋ฅผ ์ €์žฅํ•  ์ปจํ…์ŠคํŠธ์™€ ๊ณต๊ธ‰์ž๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

const DndContext = React.createContext([{}, () => {}]);

const DndCustomProvider = props => {
  const [state, setState] = useState({ dragging: false });

  return (
    <DndProvider backend={props.backend}>
      <DndContext.Provider value={[state, setState]}>
        {props.children}
      </DndContext.Provider>
    </DndProvider>
  );
};

๋‘˜์งธ, ๋Œ๊ธฐ ์‹œ์ž‘ ๊ธฐ๋Šฅ์—์„œ setTimeout์„ ์‚ฌ์šฉํ•˜๋ฉด ๋์ด ๋””์ŠคํŒจ์น˜๋˜๋Š” ๊ฒƒ์„ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  const [context, setContext] = useContext(DndContext);

  const [collected, dragRef] = useDrag({
    ...,
    begin: monitor => {
      setTimeout(() => {
        setContext(() => ({ dragging: true }));
      }, 0);

      if (begin) {
        begin(monitor);
      }
    },
    end: (item, monitor) => {
      setContext(() => ({ dragging: false }));

      if (end) {
        end(item, monitor);
      }
    },
    ...
  });

  return [
    {
      ...collected,
      isDragging: context.dragging
    },
    dragRef
  ];

๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ isDragging ์ˆ˜์ง‘๋œ ๊ฐ’์„ ์ปจํ…์ŠคํŠธ ๊ฐ’์œผ๋กœ ๋ฎ์–ด์”๋‹ˆ๋‹ค.

๋ชจ๋“  3 ๋Œ“๊ธ€

์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋งŽ์€ ๋…์„œ๋ฅผ ํ†ตํ•ด ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ํ†ตํ•ด ์ „๋‹ฌํ•˜๋Š” ์‹œ๊ฐ„ ์ œํ•œ ๋ฐ ์ƒํƒœ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ„๋‹จํ•œ ๊ฒฝ์šฐ์—๋Š” ํ•˜๊ธฐ ์‰ฝ์ง€๋งŒ ๋ณต์žกํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋‹ค์ง€ ์ข‹์•„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์ด ์ž‘๋™ํ•˜๋„๋ก ์ปจํ…์ŠคํŠธ ๋˜๋Š” ์ด์™€ ์œ ์‚ฌํ•œ ๊ฒƒ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ.
https://codesandbox.io/s/react-dnd-sortable-holes-vxeus

๋” ๋‚˜์€ ์†”๋ฃจ์…˜์„ ์•ˆ๋‚ดํ•ด ์ฃผ์…จ์œผ๋ฉด ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ๋Œ€์‹  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ isDragging์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ ํŒ€์€ ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ ๊ณต๊ธ‰์ž๋ฅผ ์œ„ํ•œ ์‚ฌ์šฉ์ž ์ง€์ • ํ›„ํฌ๋ฅผ ๋งŒ๋“œ๋Š” ์ƒํƒœ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๊ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ์— ์ง๋ฉดํ•œ ์‚ฌ๋žŒ์ด ์žˆ์„ ๊ฒฝ์šฐ ์—ฌ๊ธฐ์— ๋ฒ„๊ทธ๊ฐ€ ํ•ด๊ฒฐ๋˜๋Š” ๋™์•ˆ ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

https://codesandbox.io/s/react-dnd-sortable-gaps-custom-9tl13

์ฃผ์š” ๋ถ€๋ถ„์€ ๋“œ๋ž˜๊ทธ ์ƒํƒœ๋ฅผ ์ €์žฅํ•  ์ปจํ…์ŠคํŠธ์™€ ๊ณต๊ธ‰์ž๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

const DndContext = React.createContext([{}, () => {}]);

const DndCustomProvider = props => {
  const [state, setState] = useState({ dragging: false });

  return (
    <DndProvider backend={props.backend}>
      <DndContext.Provider value={[state, setState]}>
        {props.children}
      </DndContext.Provider>
    </DndProvider>
  );
};

๋‘˜์งธ, ๋Œ๊ธฐ ์‹œ์ž‘ ๊ธฐ๋Šฅ์—์„œ setTimeout์„ ์‚ฌ์šฉํ•˜๋ฉด ๋์ด ๋””์ŠคํŒจ์น˜๋˜๋Š” ๊ฒƒ์„ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  const [context, setContext] = useContext(DndContext);

  const [collected, dragRef] = useDrag({
    ...,
    begin: monitor => {
      setTimeout(() => {
        setContext(() => ({ dragging: true }));
      }, 0);

      if (begin) {
        begin(monitor);
      }
    },
    end: (item, monitor) => {
      setContext(() => ({ dragging: false }));

      if (end) {
        end(item, monitor);
      }
    },
    ...
  });

  return [
    {
      ...collected,
      isDragging: context.dragging
    },
    dragRef
  ];

๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ isDragging ์ˆ˜์ง‘๋œ ๊ฐ’์„ ์ปจํ…์ŠคํŠธ ๊ฐ’์œผ๋กœ ๋ฎ์–ด์”๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ํฌํ•จ๋˜์ง€ ์•Š์€ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํŒจ์น˜์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์ด๋‚˜ ์•„์ด๋””์–ด๊ฐ€ ์žˆ๋Š” ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰