react drag and drop list - TEAM-ARK/inflearn-clone-front GitHub Wiki

์ง€๋‚œ๋ฒˆ ์ˆœ์ˆ˜ javascript๋งŒ์œผ๋กœ animation์ด ์žˆ๋Š” drag and drop list๋ฅผ ๋งŒ๋“ค๋ ค๋‹ค๊ฐ€ ์ž˜ ๋˜์ง€ ์•Š์•˜๋‹ค.

javascript๋กœ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋ ค ํ–ˆ์œผ๋‚˜ ์• ๋‹ˆ๋ฉ”์ด์…˜๋ฐœ๋™ ๋„์ค‘ DOM์„ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ (DOM ์œ„์น˜๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋ฐ”๋€ ์œ„์น˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ณ„์‚ฐ์ด ์–ด๋ ต๋‹ค) ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋๋‚˜๊ธฐ ์ „์— ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ๋„์ฐฉ์ง€์ ์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ค์›Œ์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๊ณ  ์ด๋ฒˆ์— ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ณด๋ คํ•œ๋‹ค.

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋น„๊ต ๋ฐ ์„ ์ •

  • sortablejs vs react-sortable-hoc vs react dnd

sortablejs

  • Weekly Downloads : ์•ฝ 80๋งŒ
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋งŒ๋“ค์–ด์ง„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • sortablejs ์˜ˆ์ œ
  • react-sortablejs๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฆฌ์•กํŠธ์—์„œ๋„ ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉ๊ฐ€๋Šฅ
    • Weekly Downloads : ์•ฝ 8๋งŒ

react-sortable-hoc

react dnd

  • Weekly Downloads : ์•ฝ 81๋งŒ
  • drag and drop react ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋œ๋‹ค

์„ ์ • ๊ธฐ์ค€

  • inflearn ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ๊ฐ€์žฅ ์œ ์‚ฌํ•œ ๊ฒƒ
  • sortablejs๊ฐ€ ๊ฑฐ์˜ ๋˜‘๊ฐ™๊ณ  ๋‚˜๋จธ์ง„ mouseup ๊ณผ mousedown์—์„œ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์ด๋™๋˜๋Š” ๋ฐฉ์‹์ด์—ˆ๋‹ค(drag api๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž„)

sortablejs๋กœ ๊ฒฐ์ •

npm install --save react-sortablejs sortablejs
npm install --save-dev @types/sortablejs
// ์‚ฌ์šฉ ์˜ˆ - ์ฝ”๋“œ 1
const { createLectureData, lectureData, saveCourseInfoDone } = useSelector((state: RootState) => state.lecture);

const [whatYouCanLearn, setWhatYouCanLearn] = useState<ItemInterface[]>(
  lectureData?.courseInfo.whatYouCanLearn.map((item) => ({
  id: item.order,
  name: item.name,
  }))
);

<ReactSortable list={whatYouCanLearn} setList={setWhatYouCanLearn} animation={200} handle=".handle">
  {whatYouCanLearn.map((item, index) => (
    <TextListBox key={item.id} item={item} list={whatYouCanLearn} setList={setWhatYouCanLearn} index={index} />
  ))}
</ReactSortable>
// react-sortablejs์—์„œ ๊ถŒ์žฅํ•˜๋Š” item type interface - ์ฝ”๋“œ 2
export interface ItemInterface {
    /** The unique id associated with your item. It's recommended this is the same as the key prop for your list item. */
    id: string | number;
    /** When true, the item is selected using MultiDrag */
    selected?: boolean;
    /** When true, the item is deemed "chosen", which basically just a mousedown event. */
    chosen?: boolean;
    /** When true, it will not be possible to pick this item up in the list. */
    filtered?: boolean;
    [property: string]: any;
}

// ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” item์˜ type - ์ฝ”๋“œ 3
export type LectureInfoChild = {
  name: string;
  order: number | string;
};

// react-sortablejs์— ๋งž๊ฒŒ ๋ณ€ํ˜• - ์ฝ”๋“œ 4
useEffect(() => {
  setWhatYouCanLearn(
    lectureData?.courseInfo.whatYouCanLearn.map((item) => ({
    id: item.order,
    name: item.name,
    }))
  );
}, [lectureData?.courseInfo]);

key !== index

  • react-sortablejs ๊ณต์‹ ๋ฌธ์„œ์— key๋ฅผ ๋ฐฐ์—ด์˜ index๋กœ ์‚ฌ์šฉํ•˜์ง€ ๋ง๋ผ๊ณ  ํ•œ๋‹ค.

DO NOT use the index as a key for your list items. Sorting will not work.

In all the examples above, I used an object with an ID. You should do the same!

I may even enforce this into the design to eliminate errors.

๊ณ ์ฐฐ

  • ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ํƒ€์ž…์ด ๋งž์ง€ ์•Š์œผ๋ฉด ์ผ๋ถ€๋กœ ํƒ€์ž…์„ ๋งž์ถ”๋ ค๋Š” ์ฝ”๋“œ๋“ค์ด ์žˆ๋‹ค.(์ฝ”๋“œ 4๊ฐ™์€ ๊ฒฝ์šฐ) ํƒ€์ž…์„ ๋งž์ถ”๊ธฐ ์œ„ํ•œ ์ด๋Ÿฐ ๊ฒƒ์ด ์ž˜ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ธ์ง€ ์•„๋‹Œ์ง€ ์Šค์Šค๋กœ ํŒ๋‹จํ•˜๊ธฐ ์–ด๋ ค์šด ๊ฒƒ ๊ฐ™๋‹ค.

  • react-sortablejs์—์„œ ๋ฆฌ์ŠคํŠธ ์•„์ดํ…œ์˜ ์ „์ฒด๊ฐ€ ์•„๋‹Œ ํŠน์ • ๋ถ€๋ถ„๋งŒ ๋“œ๋ž˜๊ทธ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ(ํ•ธ๋“ค์„ ์‚ฌ์šฉ) ์ฝ”๋“œ 1์—์„œ ReactSortable์ปดํฌ๋„ŒํŠธ์˜ handle=".handle" ์†์„ฑ์—์„œ ํด๋ž˜์Šค ์ด๋ฆ„์„ ์ง€์ • ํ›„ ์•„์ดํ…œ ์ปดํฌ๋„ŒํŠธ์˜ ํ•ธ๋“ค ๋ถ€๋ถ„์— ํด๋ž˜์Šค ์ด๋ฆ„์„ ๋งž์ถฐ์ฃผ๋ฉด ๋œ๋‹ค.

    <DynamicBox>
      <div>{item.name}</div>
      <div>
        <button onClick={onClickDelete} type="button">
          <DeleteIcon />
        </button>
        <DraggableButton className="handle"> // ํ•ธ๋“ค์„ ์œ„ํ•œ ํด๋ž˜์Šค ์ด๋ฆ„ ์ง€์ •
          <DragHandleIcon />
        </DraggableButton>
      </div>
    </DynamicBox>

๊ฐœ์ธ ๋ธ”๋กœ๊ทธ ์›๋ฌธ

โš ๏ธ **GitHub.com Fallback** โš ๏ธ