AdminMenu.svelte 마무리

손대중·2022년 5월 7일
0

실제 메뉴 데이터를 호출하고 메뉴 생성하는 것까지 완료한 상태다.

다만 짜잘한 오류 수정 및 미세 조정이 필요하다.

부모 - 자식 컴포넌트 간 교류

AdminMenu.svelteMenuSelect.svelte 는 부모 - 자식 컴포넌트 관계다.

AdminMenu.svelteMenuSelect.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);

dispatch 란??

svelte 에서 자식 컴포넌트가 부모 컴포넌트에 알려주는 방법이 2가지가 있다.

  1. 부모 컴포넌트가 넘겨준 함수 호출
  2. svelte 에서 제공하는 dispatcher 를 통해 이벤트 발생

뭐 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 관련 추가 개발 마무리를 지어보자.

0개의 댓글