본문 바로가기

Front-End/Vue.js

Vue Warn 사례

[Vue warn]: Property was accessed during render but is not defined on instance.

원인 : 구성요소의 데이터 옵션은 함수입니다. Vue는 새 구성 요소 인스턴스를 생성하는 과정의 일부로 이 함수를 호출합니다. Vue는 반응형 시스템에 래핑하고 $data로 구성 요소 인스턴스에 저장하는 객체를 반환해야 합니다.

방법 : data() {}, 문 안에 return {} 추가

data() {
    return {}
  },

 


[Vue warn]: Invalid prop: type check failed for prop "value". Expected String with value "0", got Number with value 0.

원인 : InputText , InputBase 라는 공통 컴포넌트 vue에 props : String 만 들어가게 설정되어 있음

방법 1 : 아래와 같은 코드를 변경함

props: {
    value: String,
  },
props: {
    value: [String, Number],
  },

방법 2 : 아래와 같이 row Data 가 삽입 될 때 toString(); 처리 해줌

methods: {

    //input Text Value가 String만 들어가도록 변경 , 공통 컴포넌트 변경을 할 수 없다는 가정하에 만들어둔 메서드
    columnToStr(row) {
      row.COLUMN_NM = row.COLUMN_NM.toString();
      row.DATA_TYPE = row.DATA_TYPE.toString();
      row.DATA_SIZE = row.DATA_SIZE.toString();
      row.CMMNT = row.CMMNT.toString();
      row.RMK = row.RMK.toString();
    },
//컬럼 리스트 조회
    async fn_getColList(data) {
      const params = {
        tableNm: data,
        pageNum: this.pageInfo.page,
        pageSize: this.pageInfo.pageSize
      };

      await axios.post(process.env.VUE_APP_API_URL+'/getData.do', params)
        .then(response => {
          this.colList = response.data.map(item => {
            this.columnToStr(item); // 각 row에 대해 columnToStr 메소드 호출
            return {...item, isOriginalData: true};
          });
          this.colList.length != 0 ? this.pageInfo.totalCount = this.colList[0].TOTAL_CNT : this.pageInfo.totalCount = 0
        })
        .catch(error => {
          console.log('error >> ' + error)
        })
    },

[Vue warn] : Invalid prop: type check failed for prop "value". Expected String | Number, got Object

at <InputCheck id= Object value= Object modelValue= Array(0) ... >

원인 : CheckBox Component에 String 만 들어갈 수 있게 설정 되어 있지만 현재 Object를 삽입해주는 중

해결1 : CheckBox :id, :value를 컬럼 명으로 변경 checkIndex 배열은 자연스럽게 선택한 컬럼명만 가지고 있는 배열로 변

<template v-if="colList.length !== 0">
                          <tr v-for="(row, index) in colList" :key="`${row}` + index">
                            <td class="text-center">
                              <CheckBox :id="row.COLUMN_NM" :value="row.COLUMN_NM" v-model="checkedIndex" :key="index" />
                            </td>
                            <td class="text-start">
                              <InputText v-model:value="row.COLUMN_NM" :readonly="fn_rowReadonly(row)" />
                            </td>
                            <td class="text-start">
                              <InputText v-model:value="row.DATA_TYPE" :readonly="fn_rowReadonly(row)" />
                            </td>
                            <td class="text-end">
                              <InputText v-model:value="row.DATA_SIZE" :readonly="fn_rowReadonly(row)" />
                            </td>
                            <td class="text-start">
                              <InputText v-model:value="row.CMMNT" :readonly="fn_rowReadonly(row)" />
                            </td>
                            <td>
                              <InputText v-model:value="row.RMK" />
                            </td>
                          </tr>
                        </template>

해결2 : allSelected 함수는 row.COLUMN_NM 을 기준으로 작동하게 끔 변경

수정 전 :

allSelected: {
      //getter
      get: function() {
        return this.colList.length === this.checkedIndex.length;
      },
      //setter
      set: function(e) {
        this.checkedIndex = e ? this.colList : [];
      },
    },

수정 후 :

allSelected: {
      //getter
      get: function() {
    // 모든 `colList` 항목의 ID가 `checkedIndex`에 포함되어 있는지 확인
        return this.colList.every(row => this.checkedIndex.includes(row.COLUMN_NM));
      },
      set: function(value) {
        // `value`가 참이면 모든 항목의 ID를 `checkedIndex`에 할당, 거짓이면 빈 배열 할당
        this.checkedIndex = value ? this.colList.map(row => row.COLUMN_NM) : [];
      }
    },

행 삭제 코드 또한 변경

수정 전 :

fn_removeRow() {

      let indicesToRemove = this.checkedIndex.map(checkedItem => 
        this.mrtColList.findIndex(item => item === checkedItem)
      );

      console.log("indicesToRemove", indicesToRemove);
      indicesToRemove.sort((a, b) => b - a); // 역순으로 정렬하여 뒤에서부터 삭제
      indicesToRemove.forEach(index => {
        this.mrtColList.splice(index, 1);
      });
      this.checkedIndex = []; // 선택된 행 초기화
    },

수정 후 :

fn_removeRow() {

      let indicesToRemove = this.checkedIndex.map(checkedItem => 
        this.mrtColList.findIndex(item => item.COLUMN_NM === checkedItem.COLUMN_NM)
      );

      console.log("indicesToRemove", indicesToRemove);
      indicesToRemove.sort((a, b) => b - a); // 역순으로 정렬하여 뒤에서부터 삭제
      indicesToRemove.forEach(index => {
        this.mrtColList.splice(index, 1);
      });
      this.checkedIndex = []; // 선택된 행 초기화
    },

[Vue warn] : Extraneous non-props attributes (bizCodeList) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. at <MrtColumn tableNm="" bizCodeList= (2) [{…}, {…}] > at <MetaMgmt onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) {setTableNm: ƒ, setBizCodeList: ƒ, …} > > at <RouterView> at <RouterSection onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) {…} > > at <RouterView> at <DefaultLayout key=1 > at <App>

원인 : props를 내려주는곳에서 정상적으로 받고있지 않았음

해결 : MrtTable에 bizCodeList v-bind 해준 후 받는 코드 추가

<BizCode v-on:chgBizCodeList="setBizCodeList"/>
    <MrtTable v-on:changeTableNm="setTableNm" :bizCodeList="propsbizCodeList"/>
    <MrtColumn :tableNm="propsTableNm"/>
    <UserAuthority />
props: ['bizCodeList'],

[Vue warn]: Write operation failed: computed property "bizCd" is readonly. at <InputBase onUpdate:value=fn readonly=true placeholder="" ... > at <InputText value="전압" onUpdate:value=fn readonly=true ... > at <MrtTable onChangeTableNm=fn<bound setTableNm> bizCodeList= Array(2) > at <MetaMgmt onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > > at <RouterView> at <RouterSection onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > > at <RouterView> at <DefaultLayout key=1 > at <App>

bizCd는 computed 속성이며 실제로 coputed method 외에서는 변경이 이루어지면 안되는 구조다.

이를 개선하기 위해 아래의 코드를 변경하였다.

v-model 삭제

<InputText v-model:value="bizCd" :readonly="readonly" :placeholder="placeholder"/>
<InputText :value="bizCd" :readonly="readonly" :placeholder="placeholder"/>

[Vue warn]: Extraneous non-emits event listeners (propModalChg) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the "emits" option.

emits: ['propModalChg'],

부모 vue 컴포넌트에 커스텀 이벤트를 emit를 동작시킬때 자손 컴포넌트에 해당 메서드를 emit 표시해줘야 해당 warn을 지울 수 있다!