-
[Svelte] Svelte 기초 - Svelte로 Form 다루기 / Custom Event Dispatch하기Frontend 2020. 6. 21. 21:01
Form 다루기
이제 svelte에서 input 요소들을 어떻게 다루는 지 살펴보도록 하자.
- Input Text
- AddPersonForm.svelte
<script> let name; let hairColor; let age; const handleSubmit = () => { console.log(name, hairColor, age); }; </script> <h3>Add a new person</h3> <form on:submit|preventDefault={handleSubmit}> <input type="text" placeholder="name" bind:value={name} /> <input type="text" placeholder="hair color" bind:value={hairColor} /> <input type="number" placeholder="age" bind:value={age} /> <button>Add Person</button> </form>
먼저 form 태그에 3가지 input 태그를 만들고 각 input에 변수를 binding했다.
그리고 handleSubmit 함수를 form 태그에 submit 이벤트로 등록해주었다.
이 때 지난 번에 소개한 preventDefault라는 Event modifier를 이용하여 form 태그의 기본 동작을 막아주었다.
이제 form 태그 안에 있는 button을 클릭하면 submit 이벤트가 발생하여 handleSubmit 함수가 실행될 것이다.
(bind:value는 아래 글에서 자세히 설명했으므로 설명은 pass~)
https://im-developer.tistory.com/205
- Checkbox
<script> let name; let age; let fighting = false; let sneaking = false; let running = false; </script> <h3>Add a new person</h3> <form on:submit|preventDefault={handleSubmit}> <input type="text" placeholder="name" bind:value={name} /> <input type="number" placeholder="age" bind:value={age} /> <h4>Skills:</h4> <label> <input type="checkbox" bind:checked={fighting} />fighting<br /> </label> <label> <input type="checkbox" bind:checked={sneaking} />sneaking<br /> </label> <label> <input type="checkbox" bind:checked={running}/>running<br /> </label> <button>Add Person</button> </form>
input text나 number는 bind:value를 이용해 바인딩했으나
문제는 checkbox와 같은 태그이다.
한 가지 방법은 각 checkbox 별로 boolean 값을 가지는 변수를 만들고
checked 속성을 bind해주는 방법이다.
그러나 이렇게 했을 경우 checkbox 개수만큼 변수의 개수가 늘어나 코드가 지저분해 진다는 단점이 있다.
<script> let name; let age; let skills = []; const handleSubmit = () => { console.log(skills); }; </script> <h3>Add a new person</h3> <form on:submit|preventDefault={handleSubmit}> <input type="text" placeholder="name" bind:value={name} /> <input type="number" placeholder="age" bind:value={age} /> <h4>Skills:</h4> <label> <input type="checkbox" bind:group={skills} value="fighting" />fighting<br /> </label> <label> <input type="checkbox" bind:group={skills} value="sneaking" />sneaking<br /> </label> <label> <input type="checkbox" bind:group={skills} value="running" />running<br /> </label> <button>Add Person</button> </form>
이 경우에는 이렇게 배열을 먼저 선언하고,
각 checkbox에 bind:group을 이용하여 배열을 바인딩하면 된다.
이제 Form에서 fighting과 sneaking을 체크한 후에 버튼을 클릭하고 console 창을 확인해보면,
이렇게 skills 배열에 fighting과 sneaking이 들어와있는 것을 확인할 수 있다.
- Select
<script> let name; let hairColor; let age; let skills = []; const handleSubmit = () => { console.log(name, hairColor, age, skills); }; </script> <h3>Add a new person</h3> <form on:submit|preventDefault={handleSubmit}> <input type="text" placeholder="name" bind:value={name} /> <input type="number" placeholder="age" bind:value={age} /> <h4>Skills:</h4> <label> <input type="checkbox" bind:group={skills} value="fighting" />fighting<br /> </label> <label> <input type="checkbox" bind:group={skills} value="sneaking" />sneaking<br /> </label> <label> <input type="checkbox" bind:group={skills} value="running" />running<br /> </label> <h4>hairColor:</h4> <select bind:value={hairColor}> <option value="black">black</option> <option value="orange">orange</option> <option value="brown">brown</option> <option value="silver">silver</option> </select> <button>Add Person</button> </form> <style></style>
select 태그에도 bind:value를 사용하여 바인딩할 수 있다.
이 경우에 바인딩된 hairColor 변수에는 option 태그의 value 값이 들어간다.
Custom Event Dispatching
만약에 AddPersonForm 내부에서 submit 이벤트가 실행됐을 때,
각 변수에 저장된 input 값들이 AddPersonForm 상위 컴포넌트에 선언된
데이터에 추가되려면 어떻게 할 수 있을까?
Event forwarding을 떠올릴 수도 있겠지만, Event forwarding의 경우
하위 컴포넌트에 이벤트 handler가 등록되어 있지 않을 때 부모 컴포넌트의 handler를 그대로 가져와 사용한다는 개념으로,
하위 컴포넌트에서 특정 데이터를 상위로 넘겨 줄 방법은 없다.
이처럼 하위에서 상위로 데이터 전달을 해야 하는 경우
Custom Event dispatcher를 이용할 수 있다.
JavaScript의 Custom Event 기능을 이용한 기능인데, svelte에서 쉽게 사용하도록 여러 메소드를 제공한다.
(Custom Event는 예전에 아래 포스팅에서 한 번 다뤄본 적이 있다.)
https://im-developer.tistory.com/190?category=846746
<script> import { createEventDispatcher } from 'svelte'; let dispatch = createEventDispatcher(); let name; let hairColor; let age; let skills = []; const handleSubmit = () => { const person = { name, hairColor, age, skills, id: Math.random() }; dispatch('addPerson', person); }; </script>
일단 event를 생성하려면 svelt에서 제공하는 'createEventDispatcher' 함수를 import한다.
그리고 이 함수를 실행하여 dispatch라는 함수를 생성한다.
이 함수는 2가지 parameter를 넣을 수 있는데,
하나는 string으로 custom event의 이름이 된다.
두 번째 parameter로는 Custom event handler에 넘겨 줄 데이터를 넣을 수 있다.
이제, handlerSubmit이 실행되면, addPerson이라는 이름의 Custom Event가 생성된 후,
person 이라는 데이터와 함께 이벤트가 dispatch된다.
<script> import Modal from './Modal.svelte'; import AddPersonForm from './AddPersonForm.svelte'; let showModal = false; const toggleModal = () => { showModal = !showModal; }; let people = [ { name: 'juno', hairColor: 'brown', age: 25, id: 1 }, { name: 'mario', hairColor: 'black', age: 45, id: 2 }, { name: 'lily', hairColor: 'pink', age: 35, id: 3 }, ]; const addPerson = ({ detail: person }) => { people = [person, ...people]; showModal = false; }; </script> <Modal {showModal} on:click={toggleModal}> <AddPersonForm on:addPerson={addPerson} /> </Modal>
그러면 이제 AddPersonForm 컴포넌트를 사용하는 곳에서
아까 지정한 Custom Event의 name을 그대로 사용하여 on: 과 함께 어떤 특정 함수를 이벤트 handler로 등록할 수 있다.
이벤트 handler로 등록된 함수는 event 객체를 파라미터로 받는데,
그 객체의 detail 속성으로 person 데이터가 들어오게 된다.
이제 이 person 데이터를 이용해, 부모 컴포넌트에 선언 된 데이터에
새로운 데이터를 추가, 삭제, 수정 등 여러 조작을 할 수 있게 된다.
여기서 꼭 주의해야 하는 점은 svelte에서는 어떤 변수가 재할당될 때
그 변수와 연관된 모든 dom이 reactive하게 반응한다.
따라서 배열이나 객체 변수가 있다면 해당 배열이나 객체를 복사한 후,
재할당해주는 방식으로 업데이트해야만 reactive한 app을 개발할 수 있다.반응형'Frontend' 카테고리의 다른 글
[Kent C. dodds - Epic React] React hooks(1) - Lazy initial state / useRef (252) 2020.10.25 알아두면 유용한 TypeScript의 Utility type 정리 (252) 2020.06.21 [Svelte] Svelte 기초 - Svelte로 Modal 만들기 (Conditional Styles / Event Forwarding / Props / Event Modifiers / Slots) (253) 2020.06.21 [Svelte] Svelte 기초 - Loop / If-else blocks / Inline Event Handlers (252) 2020.06.21 [Svelte] Svelte 기초 - Data binding과 Reactive Values (252) 2020.06.02 COMMENT