Front-End

[Vue.js] 컴포넌트(component) 사용시 props옵션에 값이 넘어오지 않을 때 처리하는 방법

컴포넌트는 부모-자신 관계 뷰에서 일반적으로 사용되는 방법입니다. Vue에서 부모-자식 컴포넌트 관계에서

부모는 props(아래) 통해서 자식에게 데이터를 전달하고, 자식은 events(위) 통해서 부모에게 데이터들 전달할 수 있어요.

 

<예시 carDetail.vue>

하나의 CarDetail.vue(가칭) 컴포넌트 페이지가 v-tabs 콤포넌트를 사용하여 여러개의 탭으로 구성되어 있습니다. 각 탭은 콤포넌트 뷰로 생성해둔 후 import하여 사용하고 있어요.  생성한 컴포넌트 뷰를 import 해주고, components{} 속성에 등록해서 사용되고 있습니다.

<template>
  <v-container>
    <!--상단탭-->
    <v-tabs class="sample-tabs"
      grow
      background-color="white"
      color="cyan darken-1" v-model="active_tab">
      <v-tab v-for="item in baseTabs" :key="item.id"
        v-show="item.enable === 'Y'"
        @click="movePage(item.id)">{{item.name}}</v-tab>
    </v-tabs>
    <component :is="currentView" :carId="data.carId" :madebyId="data.madebyId"/>
  </v-container>
</template>

<script>
import Info from '@/views/components/CarInfo.vue';
import Memo from '@/views/components/CarMemo.vue';
import Feedback from '@/views/components/Feedback.vue';

export default {
  name: 'CarDetail',
  components: {
    Info,
    Memo,
    Feedback,
  },
  computed: {
  },
  data: () => ({
    currentView: 'Info',
    baseTabs: [
      { id: 'Info', name: '차량정보', enable: 'Y' },
      { id: 'Memo', name: '메모', enable: 'N' },
      { id: 'Feedback', name: '피드백', enable: 'N' },
    ],
    data: {
      carId: '',
      madebyId: '',
      selectedTab: 'Info',
      isCustom: false,
    },
    active_tab: 0,
  }),
  async created() {
      if (this.$route.params.carId !== undefined) {
        this.data.carId = this.$route.params.carId;
        this.data.madebyId = this.$route.params.madebyId;
        this.data.selectedTab = 'Info';
        this.data.isCustom = this.$route.params.isCustom;
      }
  },
  mounted() {
  },
  methods: {
    movePage(id) {
      this.currentView = id;
    },
  },
};
</script>

 

CarInfo.vue 콤포턴트 뷰에 새로운 파라미터값을 추가하여 사용해야 했고, 파라미터값을 전달해주려고 보니, 부모페이지의 파라미터값을 사용할 수 있도록 props를 선언을 해둔 상태였습니다. props를 이용해 데이터를 전달하는 방법을 사용중인것이죠. 

 

<CarInfo.vue>

<template>
  <v-container>
    <v-layout row wrap style="border-bottom:none;">
      <v-flex>
        <div>
          <v-card v-for="(item, i) in carList" :key="i">
            <v-card-title>
              <p class="name">{{ item.CAR_NM }}&#40;{{ item.MANIFEST }}&#41;</p>
            </v-card-title>
            <v-card-text>
              <p v-html="convertNewLineToBrTag(item.CAR_MEMO_TXT)"></p>
              <div>
                <v-btn
                  elevation="1"
                  icon color="#0097A7"
                  v-show="option.USE_CAR_MEMO_EDIT_YN === 'Y'
				  @click="memoDetail(item)">
                  <v-icon>mdi-playlist-edit</v-icon>
                </v-btn>
              </div>
            </v-card-text>
          </v-card>
        </div>
      </v-flex>
    </v-layout>   
  </v-container>
</template>

<script>
export default {
  name: 'CarInfo',
  props: {
    carId: { type: String },
    madebyId: { type: String },
  },
  data: () => ({
    page: {
      totCnt: 0,  
      rowPerPage: 10, 
      currPage: 1, 
    },
    data: {
      customerId: '',
    },
    carList: [],
    dialogIsShow: false,
  }),
  created() {
    this.data.customerId = this.$store.getters.getCustomerId;
  },
  mounted() {
    this.inqueryCarInfo();
  },
  methods: {
    morePage() {
      this.page.currPage += 1;
      this.inqueryCarInfo('MORE');
    },
    memoDetail(row) {
      this.dialogIsShow = !this.dialogIsShow;
      const dataRow = row;

      this.memoSave = [];
      if (dataRow) {
        this.memoSave = JSON.parse(JSON.stringify(row));
        .........생량.................
      }
    },
    convertNewLineToBrTag(str) {
      let strValue = str;
      if (strValue) {
        strValue = strValue.replace(/(?:rn|r|n)/g, '<br />');
      } else {
        strValue = '';
      }
      return strValue;
    },    
    inqueryCarInfo(isMore) {
      if (isMore !== 'MORE') {
        this.page.currPage = 1;
        this.carList = [];
      }
      const params = {
        action: 'CAR001',
        acType: 'Q_LIST',
        contactiontId: this.carId,
        companyId: this.madebyId,
        searchStr: '',
        startIndex: Number(this.page.currPage - 1) * this.page.rowPerPage,
        endIndex: this.page.rowPerPage,
      };

      this.axiosCall(params).then((rs) => {
        if (rs.data.errorCode === 'MSG0001' || rs.data.errorCode === 'MSG0006') {
          this.page.totCnt = rs.data.rowCount;

          const dataRow = rs.data.resultList;
          const e = dataRow[0];

          if (isMore !== 'MORE') this.carList = e;
          else e.forEactionh((item) => { this.carList.push(item); });
        }
      });
    },
  },
};
</script>

모든 컴포넌트는 하위 컴포넌트의 템플릿에서 상위(부모) 뷰의 데이터를 직접 참조가 불가능합니다.

그럼으로 props옵션을 사용해서만 하위 컴포넌트로 데이터를 전달 할 수 있습니다.

그래서 props에 추가해 주었습니다. 

  props: {
    carId: { type: String },
    madebyId: { type: String },
    isCustom: { type: Boolean },  // 신규 추가
  },

그러나 동작하지 않았어요. 무엇을까? 설마 이페이지도 <keep-alive> 설정이 되어 있는 페이지인가? 라는 생각에 확인해보았지만 그렇지 않았습니다. 로그값도 찍어보고 그렇게 이것 저것 해보기를 1시간 남짓….삽질을 했고, 소스 코드를 처음 부터 다시 분석해보면서 파라미터값이 전달 되지 않는 원인을 찾았습니다.

해결 방법은 부모창에서(CarDetail.vue) 콤포넌트을 바인딩 처리하는 부분에 파라미터 값을 추가해 주어야합니다.

componets :is 를 사용하고 있었네요.

 

[AS-IS]

   <component :is="currentView" :carId="data.carId" :madebyId="data.madebyId"/>

[TO-BE]

    <component :is="currentView" :carId="data.carId" :madebyId="data.madebyId"
    :isCustom="data.isCustom" />

오늘도 하나 배우고 갑니다.

 

[연관 태그]

#Vue 컴포넌트 데이터 전달, #Vue props, #Vue component:is, #Vue props 객체 전달, #vue.js props 예제, vue props 전달

 

[연관자료]

 

Components Basics — Vue.js

Vue.js – The Progressive JavaScript Framework

vuejs.org

 

 

Leave a Reply

error: Content is protected !!