๐Ÿ” ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค FE ๋ฐ๋ธŒ์ฝ”์Šค 5๊ธฐ TIL 231102

Jun 2k (Jun2)ยท2023๋…„ 11์›” 3์ผ
1

๐Ÿ’ป Intro

๋กœํ†  ๊ฐ•์‚ฌ๋‹˜์˜ ๋ฐ”๋‹๋ผ JS ๊ฐ•์˜ ๋Œ€์žฅ์ •์˜ ๋งˆ์ง€๋ง‰ ๋‚ ์ด์—ˆ๋‹ค.
๊ธด ์‹œ๊ฐ„ ๋™์•ˆ ๋ฐ”๋‹๋ผ JS๋กœ UI๋ฅผ ๊ฐœ๋ฐœํ•  ๋•Œ ๊ณ ๋ คํ•ด์•ผ ํ•  ๋งŽ์€ ํฌ์ธํŠธ๋“ค์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์–ด ์ข‹์€ ๊ฑฐ ๊ฐ™๋‹ค.
์˜ค๋Š˜์€ ๋“œ๋ž˜๊ทธ ์ด๋ฒคํŠธ์™€ ๋น„๋™๊ธฐ ํ”„๋กœ์„ธ์Šค๋ฅผ ํ ์ž๋ฃŒ๊ตฌ์กฐ์— ๋‹ด์•„์„œ ํšจ์œจ์ ์ธ task ๊ด€๋ฆฌ๋ฅผ ํ•˜๋Š” ๋ฒ•์„ ๋ฐฐ์› ๋‹ค.



๐Ÿง ์ƒˆ๋กญ๊ฒŒ ๋ฐฐ์šด ๊ฒƒ

drag ์ด๋ฒคํŠธ

Todo List์—์„œ ์™„๋ฃŒํ•œ ์ผ๊ณผ ๋ฏธ์™„๋ฃŒ ํ•œ ์ผ ๋ฆฌ์ŠคํŠธ์—์„œ ํ•  ์ผ์„ ๋“œ๋ž˜๊ทธ๋กœ ์ด๋™ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์› ๋‹ค.
drag ์ด๋ฒคํŠธ ์ค‘ dragstart, dragover,drop ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

  • dragstart : ๋งˆ์šฐ์Šค ์™ผ์ชฝํ‚ค๋ฅผ ๋ˆŒ๋Ÿฌ ๋“œ๋ž˜๊ทธ๊ฐ€ ์‹œ์ž‘๋  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค. ๋“œ๋ž˜๊ทธ์˜ ์‹œ์ž‘์ ์„ ์˜๋ฏธํ•œ๋‹ค. ์–ด๋–ค ์š”์†Œ๋ฅผ ๋“œ๋ž˜๊ทธํ•˜๋Š” ์ง€๋ฅผ ์ด ๋•Œ ์ €์žฅํ•ด์•ผ ํ•œ๋‹ค.
$todoList.addEventListener('dragstart', (e) => {
    // ๋“œ๋ž˜๊ทธ๊ฐ€ ์‹œ์ž‘๋œ ๊ณณ์—์„œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฝ‘์•„์˜จ๋‹ค.
    // ์–ด๋–ค ํ•  ์ผ์ด ๋“œ๋ž˜๊ทธ๋˜๋Š”์ง€ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•จ.
    const $li = e.target.closest('li');
	// ํ•  ์ผ id ๋ฐ์ดํ„ฐ ์ €์žฅ
    e.dataTransfer.setData('todoId', $li.dataset.id);
  });

dataTransfer : ๋“œ๋ž˜๊ทธ ์ด๋ฒคํŠธ๊ฐ€ ๊ฐ€์ง€๋Š” ๊ณ ์œ ํ•œ ๋“œ๋ž˜๊ทธ ์ž‘์—…์˜ ๋ฐ์ดํ„ฐ ๊ฐœ์ฒด์ด๋‹ค.
dragstart ์ด๋ฒคํŠธ์—์„œ๋Š” setData ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํด๋ฆญํ•œ ํ•  ์ผ์˜ id๋ฅผ ๋ฐ์ดํ„ฐ ์…‹์—์„œ ๊บผ๋‚ด์„œ ์ €์žฅํ•œ๋‹ค.


  • dragover : ๋“œ๋ž˜๊ทธ ๊ฐ€๋Šฅํ•œ ์˜์—ญ ์œ„๋ฅผ ๋“œ๋ž˜๊ทธ ์ค‘์ผ ๋•Œ (์ˆ˜ ๋ฐฑ๋ฐ€๋ฆฌ์ดˆ๋งˆ๋‹ค ๋ฐœ์ƒํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.)

    ์ž ๊น ๋“œ๋ž˜๊ทธ ํ–ˆ์„ ๋ฟ์ธ๋ฐ ์ด๋ ‡๊ฒŒ ๋งŽ์ด ๋ฐœ์ƒํ•œ๋‹ค.
$todoList.addEventListener('dragover', (e) => {
  	// ๊ธฐ๋ณธ ๋“œ๋ž˜๊ทธ ๋™์ž‘ ๋ฐฉ์ง€
    e.preventDefault();
  	// dropEffect๋ฅผ ํ†ตํ•ด ์ƒˆ ์œ„์น˜๋กœ ์ด๋™ํ•˜๋Š” ์‹œ๊ฐ์  ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•œ๋‹ค.
    e.dataTransfer.dropEffect = 'move';
  });

dragover ์ด๋ฒคํŠธ์—์„œ๋Š” ์ฃผ์˜ํ•  ์ ์ด ์žˆ๋‹ค.
e.preventDefault()์œผ๋กœ ๋“œ๋ž˜๊ทธ์˜ ๊ธฐ๋ณธ ๋™์ž‘์„ ๋ง‰์ง€ ์•Š์œผ๋ฉด ์ดํ›„ ์ปค์Šคํ…€ํ•˜์—ฌ ์ง€์ •ํ•˜๋Š” ๊ธฐ๋Šฅ๋“ค์ด ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด๋‹ค.
์—ฌ๊ธฐ์„œ๋„ dropEffect๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฐ˜๋“œ์‹œ ๊ธฐ๋ณธ ๋™์ž‘์„ ๋ง‰์•„์•ผ ํ•œ๋‹ค.
์ดํ›„ drop ์ด๋ฒคํŠธ์—๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ ์šฉํ•ด์•ผ ํ•œ๋‹ค.


  • drop : drop์ด ์œ ํšจํ•œ ๋Œ€์ƒ์— ๋“œ๋ž˜๊ทธํ•˜๋Š” ์š”์†Œ๋ฅผ ๋†“์œผ๋ฉด ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
 $todoList.addEventListener('drop', (e) => {
    // ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ธฐ๋ณธ ๋™์ž‘ ๋ฐฉ์ง€
    e.preventDefault();
   	// `dragstart`์—์„œ ์ €์žฅํ–ˆ๋˜ id ๊ฐ€์ ธ์˜ค๊ธฐ
    const droppedTodoId = e.dataTransfer.getData('todoId');

    // ํ˜„์žฌ TodoList์˜ Todo๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์— ์•Œ๋ฆผ
    // ๋˜‘๊ฐ™์€ ์š”์†Œ๋กœ ๋“œ๋ž˜๊ทธ ๋“œ๋กญํ–ˆ์„ ๋•Œ ์ƒํƒœ ๋ณ€๊ฒฝ์„ ๋ง‰์Œ
    const { todos } = this.state;

    if (!todos.find((todo) => todo._id === droppedTodoId)) {
      onDrop(droppedTodoId);
    }
  });

์ถ”๊ฐ€์ ์œผ๋กœ ํ•œ ์š”์†Œ๋ฅผ ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญํ•œ ์ข…์ฐฉ์ง€๊ฐ€ ๋ณธ์ธ ์š”์†Œ์ผ ๊ฒฝ์šฐ์—๋Š” ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญํ•œ ์˜๋ฏธ๊ฐ€ ์—†๋‹ค. ๋”ฐ๋ผ์„œ ๋ถˆํ•„์š”ํ•œ ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ์œผ๋กœ api ํ˜ธ์ถœ์ด ๋ฐœ์ƒํ•˜๋ฉด ์•ˆ๋˜๋ฏ€๋กœ ์ด๋ฅผ ๋ฐฉ์ง€ํ•ด์•ผ ํ•œ๋‹ค.


ํ๋ฅผ ํ™œ์šฉํ•œ ํšจ์œจ์  ํ…Œ์Šคํฌ ๊ด€๋ฆฌ

TodoList์—์„œ๋Š” ์‚ฌ์šฉ์ž์˜ ๋‹ค์–‘ํ•œ ๋™์ž‘์ด ๋ฐœ์ƒํ•œ๋‹ค.
์ง€๊ธˆ ๋งŒ๋“  ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ, ์‚ญ์ œ ๊ธฐ๋Šฅ์œผ๋กœ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€๊ฐ€ ์กด์žฌํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž๊ฐ€ ํ•˜๋‚˜์˜ ํ•  ์ผ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋™์ž‘์‹œ์ผฐ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž.

  1. ํ•  ์ผ 1์„ ๋ฏธ์™„๋ฃŒ ๋ฆฌ์ŠคํŠธ์—์„œ ์™„๋ฃŒ ๋ฆฌ์ŠคํŠธ๋กœ ์˜ฎ๊น€
  2. ๋ฏธ์ฒ˜ ์™„๋ฃŒํ•˜์ง€ ๋ชปํ•œ ๋ถ€๋ถ„์ด ์žˆ์–ด์„œ ๋‹ค์‹œ ํ•  ์ผ 1์„ ์™„๋ฃŒ ๋ฆฌ์ŠคํŠธ์—์„œ ๋ฏธ์™„๋ฃŒ ๋ฆฌ์ŠคํŠธ๋กœ ์˜ฎ๊น€
  3. ๊ทผ๋ฐ ์•Œ๊ณ ๋ณด๋‹ˆ ์ฒ˜๋ฆฌ ์™„๋ฃŒ์ธ๊ฑฐ ๊ฐ™์•„ ๋‹ค์‹œ ์™„๋ฃŒ ๋ฆฌ์ŠคํŠธ๋กœ ์˜ฎ๊น€
  4. ์™„๋ฃŒํ•œ ์ผ์ด๋ผ์„œ ์‚ญ์ œ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฆ„

์ด๊ฒƒ์„ ๋น„๊ต์  ๋น ๋ฅธ ์‹œ๊ฐ„ ์•ˆ์— ๋™์ž‘ํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.
๊ฐœ๋ฐœ์ž์  ๊ด€์ ์—์„œ๋Š” ์œ„ ๋„ค ๊ฐ€์ง€ ๋™์ž‘์„ ์œ„ํ•ด ํ•  ์ผ์— ๋Œ€ํ•œ ์ƒํƒœ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” fetchTodos ํ•จ์ˆ˜๋ฅผ ์ด 4๋ฒˆ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค. ์ด๋™-์ด๋™-์ด๋™-์‚ญ์ œ

ํ•˜์ง€๋งŒ ํšจ์œจ์ ์œผ๋กœ api์„ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์•ž์˜ 1 ~ 3๊นŒ์ง€์˜ ๊ณผ์ •์€ ๋ฌด์‹œํ•˜๊ณ  ๊ฒฐ๊ตญ์€ ํ•  ์ผ 1์ด ์‚ญ์ œ๋œ ๊ฒƒ์ด ์ตœ์ข… ๊ฒฐ๊ณผ์ด๋‹ค.
๋”ฐ๋ผ์„œ api ์ž…์žฅ์—์„œ๋Š” ์‚ญ์ œ์— ๋Œ€ํ•œ api ํ˜ธ์ถœ๋งŒ ํ•˜๋ฉด ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

์ด๋ฅผ task ๊ด€๋ฆฌ ๊ด€์ ์—์„œ๋Š” ์ด๋™ task 1 ~ 3์„ ํ์— ์ €์žฅํ•ด๋’€๋‹ค๊ฐ€ ์‚ญ์ œ task๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋ฉด ์ด์ „ ์ด๋™ task๋“ค์€ ์ œ๊ฑฐํ•˜๊ณ  ์‚ญ์ œ task๋งŒ ๋™๊ธฐํ™”ํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ํšจ์œจ์ ์ด๋‹ค.

๋ฌผ๋ก  ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” ๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ ๊ธฐ๋ฒ•์„ ์ ์šฉํ•˜์—ฌ task 1~4 ์— ๋Œ€ํ•œ ๋™์ž‘์ด ๋‹ค ์ด๋ค„์ง„ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋„๋ก UX๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค.

// task ๊ด€๋ฆฌ ํ•จ์ˆ˜
export default function SyncTasksManager() {
  let tasks = []; // task ํ, ๋ฐฐ์—ด๋กœ ๊ตฌํ˜„
  // ๊ธฐ๋ณธ์ ์ธ move task๋Š” push
  this.addTask = (task) => {
    tasks.push(task);
  };
  // ์‚ญ์ œ task ๋ฐœ์ƒ ์‹œ ์ด์ „ move task๋Š” ์‚ญ์ œ
  this.removeTasks = (urlPattern) => {
    tasks = tasks.filter((task) => !task.url.includes(urlPattern));
  };
  // ์ตœ์ข… ์‹คํ–‰์€ ์ˆœ์„œ๋Œ€๋กœ shiftํ•˜์—ฌ api ์š”์ฒญ ๋ณด๋‚ด๊ธฐ
  this.run = async () => {
    // task๊ฐ€ ์—†์„ ๋•Œ๊นŒ์ง€ ์žฌ๊ท€
    if (tasks.length > 0) {
      const task = tasks.shift();

      await request(task.url, {
        method: task.method || 'GET',
      });

      this.run();
    }
  };
}

์ด์ฒ˜๋Ÿผ ์‚ฌ์šฉ์ž์˜ ๋™์ž‘์— ๋”ฐ๋ผ ๋ฌด์กฐ๊ฑด์ ์œผ๋กœ api ํ˜ธ์ถœ์„ ๋ฌด๋ถ„๋ณ„ํ•˜๊ฒŒ ์š”์ฒญํ•˜๋ฉด ์„œ๋ฒ„์— ๊ณผ๋„ํ•œ ๋ถ€ํ•˜๊ฐ€ ๊ฑธ๋ฆฌ๊ณ  ๋น„์šฉ์ ์ธ ๊ด€์ ์—์„œ๋„ ๋‚ญ๋น„๊ฐ€ ์‹ฌํ•˜๋‹ค.
๋”ฐ๋ผ์„œ ๊ฐœ๋ฐœ์ž๋Š” ์‚ฌ์šฉ์ž์˜ ๋™์ž‘์— ์˜ํ•ด ์ตœ์ข…์ ์œผ๋กœ ๋„์ถœ๋˜๋Š” ๊ฒฐ๊ณผ์— ๋Œ€ํ•ด ์‹ฌ์‚ฌ์ˆ™๊ณ ํ•˜์—ฌ ๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ์™€ ์ด๋Ÿฌํ•œ ํ task ๊ธฐ๋ฒ•์œผ๋กœ ์ตœ๋Œ€ํ•œ ํšจ์œจ์ ์œผ๋กœ api๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜๋‹ค.



๐Ÿ™„ ๋” ๊ณต๋ถ€ํ•ด์•ผ ํ•  ๊ฒƒ

๋“œ๋ž˜๊ทธ ์ด๋ฒคํŠธ๋กœ width ์กฐ์ •ํ•˜๋Š” ๋ฒ•

๋…ธ์…˜ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์ด๋“œ ๋„ค๋น„๋ฐ” ๊ฒฝ๊ณ„๋ฅผ ๋“œ๋ž˜๊ทธํ•˜๋ฉด ์‚ฌ์ด๋“œ ๋„ค๋น„๋ฐ”์˜ ๋„ˆ๋น„๊ฐ€ ์กฐ์ ˆ๋˜๋„๋ก ๊ตฌํ˜„ํ•ด๋ณด๊ณ  ์‹ถ์—ˆ๋Š”๋ฐ ์‹คํŒจํ–ˆ์—ˆ๋‹ค.
์ด์ œ drag ์ด๋ฒคํŠธ๋ฅผ ๋ฐฐ์› ์œผ๋‹ˆ ์ด๋ฅผ ์ ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•ด๋ณผ ๊ฒƒ์ด๋‹ค.



๐Ÿ‘€ ๋А๋‚€์ 

๐Ÿ‘ Keep

  • ๋‹จ์ˆœํžˆ ๊ฐ•์‚ฌ๋‹˜์˜ ์ฝ”๋“œ๋ฅผ ๋”ฐ๋ผ์น˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ชจ๋ฅด๋Š” ์ด๋ฒคํŠธ๋‚˜ ๊ธฐ๋ฒ•์ด ๋‚˜์˜ค๋ฉด ๋ฐ”๋กœ๋ฐ”๋กœ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐพ์•„๋ณด๊ณ  ํŒ€์›๊ณผ ๋ฉ˜ํ† , ๊ฐ•์‚ฌ๋‹˜๊ป˜ ๋ฌผ์–ด๋ณด๊ณ  ์žˆ๋‹ค. ๊ทธ๋•Œ๊ทธ๋•Œ ๋ฏธ๋ฃจ์ง€ ์•Š๊ณ  ํ•ด๊ฒฐํ•˜๊ณ  ์žˆ๋Š” ์ค‘์ด๋‹ค!

๐Ÿ˜ฑ Problem

  • ์•„์ง๊นŒ์ง€ ๋…ธ์…˜ ์ฝ”๋“œ๋ฆฌ๋ทฐ ํ”ผ๋“œ๋ฐฑ๋„ ๋ณด์™„ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์„ ์†๋„ ๋ชป๋Œ€๊ณ  ์žˆ๋‹ค. ์ฃผ๋ง์— ๊ฑธ์ณ ์ฒ˜๋ฆฌํ•ด์•ผ ๊ฒ ๋‹ค.

๐Ÿ˜œ Try

  • ๋“œ๋ž˜๊ทธ ์ด๋ฒคํŠธ๋ฅผ ๋ฐฐ์šฐ๋ฉด์„œ ๋ฏธ์ฒ˜ ์ ์šฉํ•˜์ง€ ๋ชปํ–ˆ๋˜ ๊ธฐ๋Šฅ์„ ๋– ์˜ฌ๋ ค ํ•ด๊ฒฐํ•ด์•ผ ๊ฒ ๋‹ค๊ณ  ์‚ฌ๊ณ ๋ฅผ ์—ฐ๊ฒฐํ–ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์ƒˆ๋กœ ๋ฐฐ์šด ๋‚ด์šฉ์„ ๋ฐ”๋กœ ์ ์šฉํ•  ๊ณณ์„ ์ฐพ๋Š” ์Šต๊ด€์„ ์œ ์ง€ํ•ด์•ผ๊ฒ ๋‹ค.


๐Ÿ˜… ํ•ด๋‹น ๋‚ด์šฉ์€ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค. ํ‹€๋ฆฐ ๋ถ€๋ถ„์ด๋‚˜ ์˜คํ•ดํ•˜๊ณ  ์žˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด ํ”ผ๋“œ๋ฐฑ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

profile
ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž ์ค€๋น„์ค‘...

0๊ฐœ์˜ ๋Œ“๊ธ€