Home ERROR-Vue3-CompositionAPI에서-동적-컴포넌트-사용하는-방법
Post
Cancel

ERROR-Vue3-CompositionAPI에서-동적-컴포넌트-사용하는-방법

😥 문제 상황

회원 관리 기능을 구현하면서 비밀번호 찾기 view에서 사용자의 진행 단계에 따라 컴포넌트가 변경되어 보여주는 페이지를 만들고 있는 중에 오류가 발생했다.

간단하게 동적 컴포넌트를 활용하여 구현하려 했으나, 기존의 Vue2 방식으로 동적 컴포넌트를 설정했더니 작동이 되지 않는 오류가 발생했다. 작동이 되지 않는 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!-- src/view/ForgotPwView.vue --> 

<template>
  <div class="forgot-pw-view">
    <header-basic :prev="true" :success="false" @prevClicked="$router.go(-1)">
      비밀번호 찾기
    </header-basic>
    <section class="forgot-pw-section">
      <p>회원님의 비밀번호를 찾기 위해서 </p>
      <p>이름, 아이디, 이메일이 필요합니다.</p>
        
      <!-- 동적 컴포넌트 --> 
      <component :is="currentComponent"> </component>
    </section>
  </div>
</template>

<script setup lang="ts">
import HeaderBasic from "@/components/basics/HeaderBasic.vue";
import TheForgotPwForm from "@/components/accounts/TheForgotPwForm.vue";
import { clickPrevButton } from "../modules/clickEvent";
import { computed } from "vue";
import { useStore } from "vuex";
    
const store = useStore();

// 현재 컴포넌트에 대한 정보
const currentComponent = computed(
  () => store.getters["account/getForgotPwCurrentTab"]
);
</script>

현재 component에 대한 정보를 currentComponent변수와 연결은 한다. 해당 변수는 vuex에 현재 컴포넌트에 대한 정보를 저장하고 있는 state를 가져온다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// src/store/accounts/account.ts

import { Module } from "vuex";
import { RootState } from "../index";

export interface AccountState {
  forgotPwCurrentTab: string;
}

export const account: Module<AccountState, RootState> = {
  namespaced: true,

  state: {
    // 현재 활성화된 컴포넌트 정보를 저장하는 state
    forgotPwCurrentTab: "TheForgotPwForm",
  },

  getters: {
    // forgotPwCuurentTan state 값을 호출하는 getters
    getForgotPwCurrentTab: (state) => {
      return state.forgotPwCurrentTab;
    },
  },

  mutations: {
    // forgotPwCurrenTab의 값을 수정하는 mutations
    SET_FORGOT_PW_CURRENT_TAB: (state, value) => {
      state.forgotPwCurrentTab = value;
    },
  },

  actions: {
    // forgotPwCurrentTab 값을 수정하는 함수를 호출하는 actions
    changeForgotPwCurrentTab: ({ commit }, value) => {
      commit("SET_FORGOT_PW_CURRENT_TAB", value);
    },
  },
};


image-20220723161532682

  • currentComponent에 컴포넌트 이름이 할당되어있는 것을 확인했지만, 화면으로는 구성되지 않는 것을 확인할 수 있다.

  • 즉, 변수에 올바른 컴포넌트 이름이 할당되는 됨에도 불구하고 페이지에는 나타나지 않는다.

  • vue2에서는 아래와 같이 컴포넌트 이름을 등록한다. Hoxy…? 이것 때문일까? 🤔

    1
    2
    3
    4
    5
    6
    7
    
    <script>
      export default {
       components: {
          componentName
       }
    }
    </script>
    



😎 해결 방법

DefineAsyncComponent 사용

공식 문서

지역적으로 컴포넌트를 등록할 때 비동기 컴포넌트를 사용할 수 있기 때문에, view에 컴포넌트를 등록하면 동적 컴포넌트를 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<template>
  <div class="forgot-pw-view">
    <header-basic :prev="true" :success="false" @prevClicked="$router.go(-1)">
      비밀번호 찾기
    </header-basic>
    <section class="forgot-pw-section">
      <p>회원님의 비밀번호를 찾기 위해서 </p>
      <p>이름, 아이디, 이메일이 필요합니다.</p>
      <component :is="currentComponent"> </component>
    </section>
  </div>
</template>

<script setup lang="ts">
import HeaderBasic from "@/components/basics/HeaderBasic.vue";
import TheForgotPwForm from "@/components/accounts/TheForgotPwForm.vue";
import { clickPrevButton } from "../modules/clickEvent";
import { computed, defineAsyncComponent } from "vue";
import { useStore } from "vuex";

const store = useStore();
    
// 이제 vuex에는 컴포넌트 이름을 기록 하는 것이 아니라, 컴포넌트 인덱스를 기록한다. 
const index = computed(() => store.getters["account/getForgotPwCurrentTab"]); // 0

// 컴포넌트를 등록하여 배열에 기록한다. 
const componentArray = [
  defineAsyncComponent(
    () => import("@/components/accounts/TheForgotPwForm.vue")
  ),
  defineAsyncComponent(
    () => import("@/components/accounts/ThePasswordChangeForm.vue")
  ),
];

// 활성화된 컴포넌트
const currentComponent = computed(() => {
  return componentArray[index.value];
});
</script>



image-20220723170740985


This post is licensed under CC BY 4.0 by the author.