[블랙커피 JS] - 데이터 추가

늘보·2021년 11월 2일
0

Vanilla JS

목록 보기
2/2

Step 2 - 데이터 추가

Todo-List라면 당연히 할 일(이 강의에서는 할일=메뉴이다. 앞으로는 메뉴라고 작성하겠다) 데이터를 추가해야 한다. 그럼 가장 먼저 input 태그를 통해 사용자가 할 일을 입력하게 되는데, React에서는 간단하게 이렇게 구현했을 것이다.

const [text, setText] = useState('')

const onChange = (e) => {
  setText(e.target.value)
}

const onSubmit = (e) => {
  e.preventDefault();
  if(e.key === 'Enter') console.log('submit 성공!')
}
<span class="mr-2 mt-4 menu-count">총 0개</span>

<form id="espresso-menu-form" onSubmit={onSubmit}>
  <input id="espresso-menu-name" type="text" onChange={onChange} />
</form>

간단하다. 그럼 이걸 JS로 변화시켜보자.

1. onSubmit 이벤트 핸들러 함수

const App = () => {
  // html에서 enter를 눌렀을 때 
  // form 태그 안에서 누르게 되면 화면이 새로고침 된다(무엇을 전송하는 동작을 하기 때문)
  document
    .querySelector('#espresso-menu-form')
    .addEventListener('submit', e => {
      e.preventDefault();
    });

  // 메뉴 이름 입력받는 부분
  // React에서는 상태에 넣어서 간단하게 구현했었는데..?

  document
    .querySelector('#espresso-menu-name')
    .addEventListener('keypress', e => {
      if (e.key === 'Enter') console.log(e.target.value);
    });
};

App();
  • 훨씬 코드가 길다. 먼저, 첫 번째 이벤트 리스너 함수에서는 submit e.preventDefault()로 화면 새로고침을 막아준 것이다. 이를 위해서 form 태그에 document.querySelector을 통해 접근해야 한다.

  • 또한, 엔터를 눌렀을 때 keypress라는 이벤트 타입을 지정해줘야 한다. 또한 이는 input 태그의 idespresso-menu-name을 가져온다.

  • 추가적으로, document.querySelector() 메서드가 너무 길기 때문에 $라는 util 함수를 추가해서 작성하도록 하겠다.
const $ = selector => document.querySelector(selector);

2. 메뉴 추가

위에 작성했던 코드에서 메뉴를 입력받는 부분을 바꿔보자.

 $('#espresso-menu-name').addEventListener('keypress', e => {
    if (e.key === 'Enter') {
      const espressoMenuName = $('#espresso-menu-name').value;
      const menuItemTemplate = espressoMenuName => {
        return `
        <li class="menu-list-item d-flex items-center py-2">
          <span class="w-100 pl-2 menu-name">${espressoMenuName}</span>
          <button
            type="button"
            class="bg-gray-50 text-gray-500 text-sm mr-1 menu-edit-button"
          >
            수정
          </button>
          <button
            type="button"
            class="bg-gray-50 text-gray-500 text-sm mr-1 menu-remove-button"
          >
            삭제
          </button>
        </li>`;
      };
      $('#espresso-menu-list').innerHTML = menuItemTemplate(espressoMenuName);
    }
  });

  • 문제가 생겼다. ul태그 사이에 li태그를 집어넣어야 해서 innerHTML 메서드를 통해 구현했는데, 데이터가 아래에 쌓여서 보여지는 형태가 아니라 계속 다른 데이터로 덮어 씌워진다.

  • 이 문제를 해결하기 위해서 innerHTML 메서드 대신 insertAdjacentHTML를 사용하였다. 이 메서드는 element 안에 존재하는 element를 건드리지 않는다.

  • inserAdjacentHTML에 대한 추가 정보: https://developer.mozilla.org/ko/docs/Web/API/Element/insertAdjacentHTML

  • 그럼 맨 아래 코드를 innerHTML 대신 insertAdjacentHTML을 적용한 코드는 다음과 같다.

$('#espresso-menu-list').insertAdjacentHTML('beforeend', menuItemTemplate(espressoMenuName));

  • 성공적으로 메뉴가 추가되었다!

Step 3 - 전체 메뉴 개수 보여주기

이제 아래 부분에 메뉴의 전체 개수를 보여줘야 한다.

 <span class="mr-2 mt-4 menu-count">총 0개</span>
  • React에서는 보통 상태값에 가져온 데이터(배열로 가져왔다고 했을 때)의 상태값.length를 보여주면 전체 데이터의 개수를 구할 수 있었다. 그러면 Vanilla JS에서는 어떻게 할까? 일단 Vanilla JS는 React처럼 상태값을 제공하지는 않는다.
const menuCount = $('#espresso-menu-list').querySelectorAll('li').length; 
  • 위의 menuCount 변수를 보자. ul태그인 #espresso-menu-list의 자식 요소인 li 태그를 querySelectorAll('li')을 통해 모두 가지고 왔다.(querySelectorAll 메서드는 배열 형태로 값을 return한다.) 이후 해당 배열의 length가 바로 전체 메뉴의 개수가 될 것이다.
  • 마지막으로 innerText 메서드를 사용해 값을 변경해준다.
 $('.menu-count').innerText = `${menuCount}`;

Step 4 - input을 빈 값으로 만들어주기

React에서는 보통 아래와 같이 Text 상태값을 '' 이렇게 빈 string을 넣어주는 방식으로 구현했을 거라고 생각한다.

const onSubmit = (e) => {
  e.preventDefault();
  if(e.key === 'Enter') console.log('submit 성공!')
  setText('')
}

Vanilla JS로는 이렇게 구현할 수 있다.

 $('#espresso-menu-name').value = '';

직접 DOM의 value 프로퍼티에 접근하는 것이다.

Step 5 - input이 빈 값이라면 메뉴가 추가되지 않게 만들기

if (!$('#espresso-menu-name').value) {
      alert('값을 입력해주세요.');
      return;
}
  • 강의에서는 alertnullreturn 함으로써 값이 없는 경우 alert 창만 뜨게 하였다.

그런데 이렇게 구현하면 맨 처음에는 항상 input에 값이 없기 때문에 alert창이 뜨게 된다. 그렇다면 어떻게 해결하면 될까?

 if (e.key !== 'Enter') return; // 추가된 부분

 if (!$('#espresso-menu-name').value) {
    alert('값을 입력해주세요.');
    return;
 }
  • 이렇게 빈 input을 검사하는 코드 위에 e.key'Enter'가 아닐 경우 nullreturn하면 된다.

Step

후기

이전에 Todo-List를 만들때의 기억으로는 innerHTML 메서드와 반복문을 사용해 만들었던 걸로 기억하는데, 이번엔 insertAdjacentHTML를 사용하였다. 처음 알게 된 메서드였는데, 더 직관적이고 사용이 편리한 것 같다.

추가적으로, React에서는 상태값을 변경하는 방식을 사용했지만, Vanilla JS에서는 주로 DOM에 직접 접근한다는 것이다. React에서는 DOM에 직접 접근하는 것이 암묵적으로 '좋지 않다'라고 알고 있었는데, Vanilla JS에서 DOM 직접 접근은 상관없는지? 의문이 생겼다.

0개의 댓글