[2์ฃผ์ฐจ ์Šคํ„ฐ๋”” ํ›„๊ธฐ/15๊ธฐ] ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ (feat. VanillaJS)

2022. 6. 16. 19:26ใ†๊ฐœ๋ฐœ/๊ฐ•์˜ํ›„๊ธฐ

๋ฒŒ์จ 2์ฃผ์ฐจ๊ฐ€ ๋˜์—ˆ๋‹ค! โœจ

์ด๋ฒˆ ๋ฏธ์…˜์€ 1์ฃผ์ฐจ์— ๋งŒ๋“ค์—ˆ๋˜ TodoList์— ๋‹ค์–‘ํ•œ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ์ถ”๊ฐ€ํ•ด์„œ TodoApp์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰๋˜์—ˆ๋‹ค. 


 

TodoApp์— ๊ธฐ๋Šฅ์ด ๋” ๋งŽ์•„์ง€๊ณ  ์ปดํฌ๋„ŒํŠธ๋“ค์ด ๋” ์ถ”๊ฐ€๋˜๋ฉด์„œ ์š”๊ตฌ์‚ฌํ•ญ์ด ์กฐ๊ธˆ ๋” ๋ณต์žกํ•ด์กŒ๋‹ค. ๊ทธ๋ž˜์„œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ํ”ผ๊ทธ๋งˆ๋ฅผ ํ†ตํ•ด ๊ฐ ์ปดํฌ๋„ŒํŠธ๋“ค์˜ ๊ตฌ์กฐ๋ฅผ ์งœ๋ฉด์„œ ๊ฐ„๋‹จํ•œ ๋””์ž์ธ ์ž‘์—…์„ ์ง„ํ–‰ํ–ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์š”๊ตฌ๋ถ„์„ · ๋””์ž์ธ · ํผ๋ธ”๋ฆฌ์‹ฑ์— ๋ฐ˜๋‚˜์ ˆ ์ •๋„์˜ ์‹œ๊ฐ„์„ ์ผ๋Š”๋ฐ, ํผ๋ธ”๋ฆฌ์‹ฑํ•  ๋•Œ ๋งจ๋‚  SCSS ์“ฐ๋‹ค๊ฐ€ ์˜ค๋žœ๋งŒ์— CSS๋กœ ํ•˜๋‹ˆ๊นŒ ๋ถˆํŽธํ•ด์„œ SCSS๊ฐ€ ์ •๋ง ๊ทธ๋ฆฌ์› ๋‹ค..

 

ํ”ผ๊ทธ๋งˆ์™€ ๊ตฟ๋…ธํŠธ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๋Š” ์ „์ฒด์ ์ธ ์•ฑ ๊ตฌ์กฐ๋ฅผ ๊ทธ๋ ธ๋‹ค.

 


๊ตฌ์กฐ๋ฅผ ์ง  ํ›„์—๋Š” ๋ณธ๊ฒฉ์ ์œผ๋กœ TodoApp์˜ ๊ฐ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๋งŒ๋“ค๊ณ , ๊ธฐ๋ณธ์ ์ธ CRUD๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

๊ทธ์ค‘์—์„œ ์ˆ˜์ •/์‚ญ์ œ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์œ ๋‹ˆํฌํ•œ id๊ฐ’์ด ํ•„์š”ํ–ˆ๋Š”๋ฐ, ์ฃผ์–ด์ง„ ๋ฐ์ดํ„ฐ๋ฅผ ์ตœ๋Œ€ํ•œ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด์„œ ๋ฐฐ์—ด์˜ index์„ ํ™œ์šฉํ•ด์„œ ๊ตฌํ˜„ํ–ˆ๋‹ค.

// ๐Ÿ“Œ render ํ•จ์ˆ˜
render() {
  this.$element.innerHTML = this.state
    .map(
      ({ text, isCompleted }, idx) =>
        `
      <li class="todo-item" data-index=${idx}>
      <label class="form-check-group">
        <input class="form-check" type="checkbox" ${
          isCompleted ? 'checked' : ''
        } />
        <span>${text}</span>
      </label>
      <button class="btn delete-button" type="button">delete</button>
    </li>
      `
    )
    .join('');
 }

// ๐Ÿ“Œ addTodo ํ•จ์ˆ˜
addTodo(newText) {
  const newData = [...this.data, { text: newText, isCompleted: false }];
  this.setState(newData);
}

// ๐Ÿ“Œ deleteTodo ํ•จ์ˆ˜ : index ๊ฐ’์„ ์‚ฌ์šฉํ•ด ๊ฐ’ ์‚ญ์ œ
deleteTodo(index) {
  const newData = this.data.filter((todo, i) => i !== parseInt(index));
  this.setState(newData);
}

// ๐Ÿ“Œ toggleTodo ํ•จ์ˆ˜
  toggleTodo(index) {
  const newData = this.data.map((todo, i) =>
    i === parseInt(index) ? { ...todo, isCompleted: !todo.isCompleted } : todo
  );
  this.setState(newData);
}

๋‹ค์Œ์œผ๋กœ๋Š” Custom Event, Local Storage๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ถ”๊ฐ€ ๊ตฌํ˜„ ์‚ฌํ•ญ์„ ์ง„ํ–‰ํ–ˆ๋Š”๋ฐ, ์ด์ฏค๋ถ€ํ„ฐ๋Š” ์ด๋ฏธ ํ•˜๋ฃจ์น˜ ๋‡Œ ์‚ฌ์šฉ๋Ÿ‰์„ ์ดˆ๊ณผํ•œ ๋А๋‚Œ์ด ๋“ค๊ณ  ๋„ˆ๋ฌด ์กธ๋ ธ๋‹ค๐Ÿ˜‚  ๊ทผ๋ฐ ์—ฌ๊ธฐ์„œ ๋ฉˆ์ถ”๊ณ  ์ž๋ฉด ์ž ์„ ์ œ๋Œ€๋กœ ๋ชป ์ž˜ ๊ฒƒ ๊ฐ™์•„์„œ ๋ช‡ ์ค„ ์•ˆ ๋˜๋Š” ๋Œ€์ถฉ์ด๋ผ๋„ ์†์ฝ”๋”ฉํ•ด๊ฐ€๋ฉด์„œ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋ถ„์„ํ•˜๊ณ  ๋กœ์ง์„ ์งฐ๋‹ค. 

 

์ปค์Šคํ…€ ์ด๋ฒคํŠธ์™€ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋Š” ์ด๋ฒˆ ๋ฏธ์…˜์—์„œ ์ฒ˜์Œ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋…๋“ค์ด๋ผ์„œ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ฐฌ์ฐฌํžˆ ์‚ดํŽด๋ณด๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์กŒ๋‹ค. ํŠนํžˆ ์ปค์Šคํ…€ ์ด๋ฒคํŠธ๋ฅผ ์–ด๋–ป๊ฒŒ ์“ฐ๋Š”์ง€ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด ์ „์ฒด์ ์œผ๋กœ ๋‹ค์‹œ ์ •๋ฆฌ๋ฅผ ํ–ˆ๋Š”๋ฐ, ๋•๋ถ„์— ์ด ๊ณผ์ •์—์„œ matches ๋ผ๋Š” ํ•จ์ˆ˜๋„ ์•Œ๊ฒŒ ๋๋‹ค! ์ง€๊ธˆ๊นŒ์ง€ ์ด๋ฒคํŠธ ์œ„์ž„ ๊ด€๋ จํ•œ ์ฝ”๋“œ๋ฅผ ์งค ๋•Œ $element.classList.contains('class')๋กœ ๊ฐ ์š”์†Œ๋“ค์„ ํ™•์ธํ–ˆ์—ˆ๋Š”๋ฐ $element.matches('.class')๋ฅผ ํ™œ์šฉํ•˜๋ฉด ํ›จ์”ฌ ๊ฐ€๋…์„ฑ์ด ์ข‹์€ ๊ฒƒ ๊ฐ™๋‹ค.

 

โœ”๏ธ ์ปค์Šคํ…€ ์ด๋ฒคํŠธ

์ปค์Šคํ…€ ์ด๋ฒคํŠธ๋กœ ๊ตฌํ˜„ํ•œ removeAll

 

// ๐Ÿ“Œ ์ปค์Šคํ…€ ์ด๋ฒคํŠธ ์‚ฌ์šฉํ•˜์—ฌ removeAll ๊ตฌํ˜„
setRemoveAll() {
    const $removeAllBtn = this.$root.querySelector('.remove-all-button');
    $removeAllBtn.addEventListener('click', () => {
      this.$root.dispatchEvent(new CustomEvent('removeAll'));
    });

    this.$root.addEventListener('removeAll', () => {
      this.setState([]);
    });
 }

 

โœ”๏ธ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€

LocalStorage๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ฆฌํŽ™ํ† ๋ง

  getState() {
    try {
      const storedState = JSON.parse(localStorage.getItem(this.name));
      return storedState ? storedState : null;
    } catch (e) {
      console.error(e);
    }
  }
 
 
 setState(nextState) {
    this.state = nextState;

    try {
      localStorage.setItem(this.name, JSON.stringify(nextState));
    } catch (e) {
      console.error(e);
    }

    this.todoCount.setState(this.state);
    this.todoList.setState(this.state);
  }

๋‚˜ ํ˜ผ์ž localStorage๋ฅผ ๊ตฌํ˜„ํ•ด๋ดค์„ ๋•Œ๋Š” ์œ„์—์„œ ์ฒ˜๋Ÿผ App์•ˆ์—์„œ ๋ชจ๋“  ์ฒ˜๋ฆฌ๋ฅผ ๋‹ค ํ•˜๋„๋ก ํ–ˆ๋Š”๋ฐ, ๋กœํ† ๋‹˜์˜ ๋ผ์ด๋ธŒ์ฝ”๋”ฉ์„ ๋ณด๋‹ˆ๊นŒ ๋”ฐ๋กœ ๋ถ„๋ฆฌ๋ฅผ ์‹œํ‚ค๋Š” ๊ฒŒ ํ™•์‹คํžˆ ์‚ฌ์šฉํ•˜๋Š” ์ž…์žฅ์—์„œ๋„, ๊ฐ€๋…์„ฑ ์ธก๋ฉด์—์„œ๋„ ํ›จ์”ฌ ์ด๋“์ด์—ˆ๋‹ค! ํ•œ ๋ฒˆ ์ œ๋Œ€๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์„ ๋ณด๊ณ  ๋‚˜์„œ ์—ฐ์Šตํ•˜๊ณ  ๋‚˜๋‹ˆ๊นŒ ์‚ฌ๋žŒ์ด ์ฐธ ๊ฐ„์‚ฌํ•œ ๊ฒŒ ๋ถˆ๊ณผ ๋ฉฐ์น  ์ „์— ์™„์„ฑํ–ˆ๋˜ ๋‚ด ์ฝ”๋“œ๊ฐ€ ๊ต‰์žฅํžˆ ๋‚ฏ์„ค์—ˆ๋‹ค..ใ…Ž...

 

export default function App({ selector, name }) {
  const storage = new Storage(name, []); // ๐Ÿ‘‰ Storage๋กœ ๋ถ„๋ฆฌํ•œ ๋ชจ์Šต 

  this.$root = document.querySelector(selector);
  this.name = name;
  this.state = storage.getItem();  // ์‚ฌ์šฉํ•˜๊ธฐ ๊ฐ„ํŽธํ•ด์กŒ๋‹ค โœจ
  
  //...

  this.setState = function (nextState) {
    this.state = nextState;
    storage.setItem(nextState); // ์‚ฌ์šฉํ•˜๊ธฐ ๊ฐ„ํŽธํ•ด์กŒ๋‹ค โœจ
    todoList.setState(this.state);
    todoCount.setState(this.state);
  };
  
 }

 

์ „์ฒด์ ์œผ๋กœ App์—์„œ ๋ชจ๋“  ์ผ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฐ ์ปดํฌ๋„ŒํŠธ๋“ค์ด render๋งŒ ํ•ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ–ˆ๋˜ ๊ฒƒ์„ function ํƒ€์ž…์œผ๋กœ ๋‹ค์‹œ ๋ฆฌํŽ™ํ† ๋งํ•ด๋ณด๋ฉด์„œ ๊ฐ ์ปดํฌ๋„ŒํŠธ๋“ค์ด ์ฑ…์ž„์„ ๋‚˜๋ˆ ๊ฐ€์ง€๋„๋ก ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์— ์ต์ˆ™ํ•ด์ง€๋„๋ก ์—ฐ์Šตํ–ˆ๋‹ค. 1์ฃผ์ฐจ๋Š” ์ •๋ง ์›Œ๋ฐ์—…์ด์—ˆ๋˜๊ฒŒ, 2์ฃผ์ฐจ๋ถ€ํ„ฐ๋Š” ๋ผ์ด๋ธŒ์„ธ์…˜์—์„œ๋„ ๋ฐฐ์šธ๊ฒŒ ์ •๋ง ๋งŽ์•˜๋‹ค. ์ฝ”๋“œ๋ฆฌ๋ทฐ๋กœ ์ •๋ง ์ƒ๊ฐ์น˜๋„ ๋ชปํ–ˆ๋˜ ๋ถ€๋ถ„๋“ค๊นŒ์ง€ ์„ธ์„ธํ•˜๊ฒŒ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›๊ณ , ๋ฐ”๋‹๋ผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๋ฆฌ์•กํŠธ์™€ ํก์‚ฌํ•˜๊ฒŒ ๊ตฌํ˜„ํ•ด๋ณด๋ฉด์„œ ์ฝ”๋“œ ์Šต๊ด€์ด ์˜ˆ์˜๊ฒŒ ์ •๋ฆฌ๋˜๋Š”๊ฒŒ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋А๊ปด์กŒ๋‹ค.  ์ข‹์€ ์ฝ”๋“œ๋ฅผ ๋ณด๊ณ  ๋”ฐ๋ผํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ ์ •๋ง ๋งŽ์ด ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹จ ์ƒ๊ฐ์ด ๋“ค์—ˆ๊ณ , ๊ทธ๋Ÿฐ ์˜๋ฏธ์—์„œ ์ด๋ฒˆ ์ฝ”๋“œ๋ฆฌ๋ทฐ ์Šคํ„ฐ๋””๊ฐ€ ์ •๋ง ๋งŽ์ด ์„ฑ์žฅํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ์ธ ๊ฒƒ ๊ฐ™๋‹ค ๐Ÿ‘ 

 

https://programmers.co.kr/learn/courses/14237

 

[์Šคํ„ฐ๋””/16๊ธฐ] ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ (feat. VanillaJS)

๐ŸŽ ์•„์‰ฝ์ง€๋งŒ 16๊ธฐ๋Š” ๋งˆ๊ฐ๋˜์—ˆ์–ด์š”. 17๊ธฐ ์˜คํ”ˆ ์•Œ๋ฆผ ์‹ ์ฒญํ•˜๊ณ , ์ตœ์ €๊ฐ€์— ์ˆ˜๊ฐ•ํ•˜์„ธ์š”! ์ตœ์ €๊ฐ€ ์•Œ๋ฆผ ๋ฐ›๊ธฐ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์˜จ๋ผ์ธ ์Šคํ„ฐ๋”” ์‹œ๋‹ˆ์–ด ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€, ์•„๋ผ๋Š”

programmers.co.kr