실제 메뉴 데이터를 호출하고 메뉴 생성하는 것까지 완료한 상태다.
다만 짜잘한 오류 수정 및 미세 조정이 필요하다.
AdminMenu.svelte
와 MenuSelect.svelte
는 부모 - 자식 컴포넌트 관계다.
AdminMenu.svelte
는 MenuSelect.svelte
를 생성하면서 select box 를 구현하기 위한 정보들 - 리스트, depth 등 - 을 넘겨준다.
{#each parents as parent, i}
<div>
<MenuSelect menus={parent.list} depth={i} on:change={changeParent} initTime={parents.initTime}></MenuSelect>
</div>
{/each}
MenuSelect.svelte
에서는 select box 에서 아이템이 선택될때마다 change 이벤트를 발생시켜 부모 컴포넌트 - AdminMenu.svelte
에게 알려준다.
const changeValue = () => {
dispatch('change', { value, depth });
};
// value 가 바뀔때마다 change 이벤트 발생
$: changeValue(value);
svelte 에서 자식 컴포넌트가 부모 컴포넌트에 알려주는 방법이 2가지가 있다.
뭐 store 를 통해 알려주는 것도 있고, 그 외에도 더 있을 수도 있는데 일단 내가 아는 선에서는 요 2가지다.
2가지 다 잘 동작하는데 숙달도 할겸 dispatcher 로 코딩했다.
svelte dispatcher 사용법은 https://svelte.dev/tutorial/component-events 링크를 참조하자.
추가로 AdminMenu.svelte
에는 메뉴 생성 성공시 select box 및 input box 를 초기화하는 코드가 들어가 있다.
const init = value => {
if (value === 'parent') {
parents = [{list: $menu, select: null}];
}
if (value === 'info') {
name = '';
}
};
menu.subscribe(value => {
init('parent');
});
const addMenu = async () => {
......
if (response?.success) {
alert(`${name} 메뉴 생성에 성공하였습니다.`);
// menu.reset() -> menu store 에서 데이터 다시 가져와 세팅 -> menu.subscribe 으로 등록된 리스너 실행 -> 데이터 초기화
menu.reset();
name = '';
} else {
alert(`${name} 메뉴 생성에 실패하였습니다.`);
}
};
다만 한가지 문제가 있었다. 메뉴 데이터를 업데이트해도 list [] 자체는 계속 있다 보니, 최소한 1번째 select box - 1번째 MenuSelect.svelte
는 계속 남아 있다 보니 select box 내 value 가 계속 유지되는 이슈가 있다. 즉, 첫번째 select box 에서 선택한 메뉴가 있으면 걔는 계속 남아 있음......
다수의 select box 가 존재하고 select box 의 선택에 따라 select box 의 노출을 하는 현 구조상 AdminMenu.svelte
에서 무조건 데이터 조정을 해야 한다.
또한 AdminMenu.svelte
에서 select 메뉴에 대한 데이터 조정을 도맡기 때문에, MenuSelect.svelte
에 select 메뉴 정보를 직접 전달하는 것도 무한 루프의 문제가 발생하게 된다.
나의 해결책은? 이게 데이터 init 인지 아닌지를 구분할 수 있도록 initTime 을 넘겨주는 것...
MenuSelect.svelte
에서는 initTime 이 변경될 경우 init 임을 인지하고 value 를 초기화한다.
AdminMenu.svelte
const init = value => {
if (value === 'parent') {
parents = [{list: $menu, select: null}];
parents.initTime = (new Date()).getTime();
}
if (value === 'info') {
name = '';
}
};
MenuSelect.svelte
// value reset 용
export let initTime;
let value;
const dispatch = createEventDispatcher();
const changeValue = () => {
dispatch('change', { value, depth });
};
const resetValue = () => {
value = undefined;
};
// value 만 감지하도록 별도의 함수로 분리
$: changeValue(value);
// initTime 만 감지하도록 별도의 함수로 분리
$: resetValue(initTime);
어 AdminMenu.svelte
에서 MenuSelect.svelte
로 init 된다고 알려주면 되는 거 아님?
안타깝게도 svelte 에서는 부모 컴포넌트에서 자식 컴포넌트로 이벤트를 발생시키는 수단을 찾지 못했다. (반대의 경우에는 dispatch
를 통해 가능)
내가 문서를 대충 찾은 건지... 아님 못 본 건지... 걍 없는 건지... 여튼 이걸로 해결함.
다음은 API 서버 - 메뉴 API 관련 추가 개발 마무리를 지어보자.