자바스크립트

[프론트엔드] HTML 태그에 type 속성을 제대로 지정하지 않으면 큰일남

취업 드가자잇 2024. 9. 4. 16:02

 

html태그의 type 속성을 정확하게 지정하는게 중요한 이유는 이벤트 충돌을 방지하고, 각 요소의 기본 동작을 제어하기 위함이다.

이렇게만 설명하면 크게 와닿지 않을 수 있는데, 최근에 이를 간과하고 개발을 하다가 잠시 당황했던 경험이 있어 공유해보고자 한다.

 

문제 상황: 두가지 이벤트가 한번에 발생

예제 (리액트)

 

이 예제는 새로운 연락처 (이름, 전화번호, 그룹) 저장하고, 이 저장된 데이터를 기반으로 오른쪽에 촤르륵 띄워주는 간단한 사이트이다. 그리고 폼 안에 있는 '조직 추가' 버튼을 누르게 되면 아래와 같은 허접한 모달창이 나와 새 그룹 옵션을 추가해줄 수 있는 기능이 있다. 

모달창 예제

 

폼 제출시 리스트에 추가되는 예시

 

보기에는 정상적으로 작동할 것 같다. 하지만 의외로 그렇지 않은데, 폼을 제출하기 위해 엔터를 누르면 예상치 못한 일이 발생하게 된다. 

일단 예상대로라면 form에서 정보를 입력하고 이를 제출했을때 바로 위 예시처럼 새로운 요소가 추가되는 이벤트만 발생해야 정상이다.

 

예상 로직

  • 폼 제출 시: 입력 후 엔터를 누르면 폼 제출 이벤트가 발생한다.
  • 조직 추가 버튼 클릭 시: 버튼 클릭 시 모달이 열리도록 설정.

 

하지만 문제는 폼 제출을 했을때 '조직 추가' 버튼을 눌렀을때만 떠야하는 모달창이 뜨고 폼 제출도 되는, 2가지의 이벤트가 동시에 발생한다는 것이다. 

 

문제 상황과 분석

<form className="inputCon" onSubmit={saveContact}>
  <InputField id="name" field="이름" value={name} setValue={setName} />
  <InputField id="phone" field="전화번호" value={phone} setValue={setPhone} />
  <SelectField
    group={group}
    setGroup={setGroup}
    selectedGroup={selectedGroup}
    setSelectedGroup={setSelectedGroup}
  />
  <InputField id="record" field="간단한 기록" />
  <button className="saveBtn" onClick={() => saveContact()}>
    저장
  </button>
</form>

<div className="selectField">
  <label htmlFor="group" className="selectLabel">그룹</label>
  <select
    name="group"
    id="group"
    value={selectedGroup}
    onChange={(e) => setSelectedGroup(e.target.value)}
  >
    {group.map((opt, i) => (
      <option key={i} value={opt}>
        {opt}
      </option>
    ))}
  </select>
  <button onClick={addOption}>조직추가</button>
  {isModalOpen && (
    <GroupModal setModal={addOption} group={group} setGroup={setGroup} />
  )}
</div>

 

 

문제의 흐름을 보면 다음과 같다.

1. 폼 내의 입력 필드에서 엔터를 누르면 폼이 제출되며 saveContact (새로운 연락처를 저장하는 로직)이 호출된다.

2. 이와 동시에 SelectField내에 있는 버튼의 addPost (모달창을 열고 새로운 옵션을 추가할 수 있는 로직)이 호출된다.

3. SelectField내에 있는 아래 예시의 버튼을 클릭해도 위와 같은 이벤트가 발생하게 된다, 즉 의도치않게 두 이벤트가 동시에 발생한다.

<button onClick={addOption}>조직추가</button>

 

결론부터 말하자면 문제의 원인은 이벤트전파였다. 

그 이유는 버튼의 type을 따로 지정하지 않게 되면 submit으로 초기화되는데, 이렇게 초기화된 버튼이 폼 제출을 트리거하고, 버튼 클릭 이벤트가 함께 호출된 것이다. 

 

  1.  

해결 방법

이제 문제의 원인을 알았으니 아주 간단하게 해결이 가능하다.

<button type="button" onClick={addOption}>
        조직추가
 </button>

 

이렇게 문제가 발생한 버튼의 type 속성을 적절히 설정하면, 해당 버튼이 폼 제출과 무관하게 독립적으로 작동하도록 제어할 수 있다. 

정리하자면, 역시 가장 중요한 건 기본기다.

  1. 이벤트 전파 제어: 클릭 이벤트와 폼 제출 이벤트를 분리하여 명확히 제어해야 함.
  2. type 속성 지정: 버튼의 type을 명확히 설정하여 불필요한 폼 제출을 방지.
    • type="button": 폼 제출과 관계없는 버튼.
    • type="submit": 폼 제출 버튼.
    • 버튼에 type="button" 추가하여 폼 제출을 방지
    • e.preventDefault() 사용하여 이벤트의 기본 동작 방지.