ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [vue] prop data 사용하기 - Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders - 비동기상황에서 props 데이터 사용하기
    프론트엔드/Vuejs 2020. 11. 18. 00:59

    vue prop data 를 사용하다가

     

    Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders

    이 오류를 본 적이 있다.

     

    이 오류가 난 경우는 props data 를 받고 이 props 데이터를 변경해주었더니 생긴 오류다.

    이 props 데이터를 위로 올리고 이 올린 데이터를 또 props 로 내려서 하위 자식에서 쓰려했더니 생긴 오류다.

     

    props 에 대한 vue 의 공식 문서 설명이다.

    일반적으로 prop을 변경시키고 싶은 유혹을 불러 일으킬 수있는 두 가지 경우가 있습니다.
    1. 이 prop는 초기 값을 전달 하는데만 사용되며 하위 컴포넌트는 이후에 이를 로컬 데이터 속성으로 사용하기만 합니다.
    2. prop는 변경되어야 할 원시 값으로 전달됩니다.

    https://kr.vuejs.org/v2/guide/components.html#%EB%8B%A8%EB%B0%A9%ED%96%A5-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%9D%90%EB%A6%84

    - vue 공식문서

     

    자식으로 내려온 props 데이터를 고치면 부모 데이터도 수시로 바뀐다고 생각했지만, 데이터 흐림이 단방향이므로 하위 데이터를 바꾼다 하더라도 부모의 데이터를 바꿀수 없었다..

     

    그래서 eventBus 를 통해서 부모의 데이터를 바꿔준다.

     

    여기까지는 괜찮지만 초기 렌더링시에 문제가 생길 수 있다.

    이유는 데이터가 비동기적인 데이터를 가져오기 때문인데, 

     

    인스턴스 생성 순서는 부모 -> 자식이며, 마운팅 순서는 자식->부모 

    이기 떄문에 비동기적으로 데이터를 부모에서 자식으로 줄때 문제가 생긴다. 이런 문제를 아래 코드를 예시로 해결하자.

     

     

    비동기적인 상황에서

    부모가 자식에게 데이터를 내려주고 부모 컴포넌트가 바뀐데이터를 받는 방법

    부모 컴포넌트

    <template>
    <date-picker
    :propDate="dateData"
    v-on:update:dateSettting="setDate"
    />
    </template>
    <script>
    export default {
      data () {
        return {
        	dateData: '' // 비동기 데이터
        }
      },
      methods: {
        get () { // 비동기호출데티어
            http
              .get('sampleUrl')
              .then(response => {
                this.dateData = response.data
              })
              .catch(e => {
               
              })
              .finally(() => {
              })
          }
        },
        setDate (value) { // 이벤트버스 호출시 실행
          this.dateData = value
        },
      }  
    </script>

    자식 컴포넌트

    <template>
      <div >
        <datepicker
          class="datepicker"
          placeholder="예) 2019-07-27"
          :language="languages['ko']"
          format="yyyy-MM-dd"
          ref="openDate"
          v-model="date"
        />
      </div>
    </template>
    
    <script>
    import Datepicker from 'vuejs-datepicker/dist/vuejs-datepicker.esm.js'
    import * as lang from 'vuejs-datepicker/dist/locale'
    
    export default {
      props: {
        propDate: String
      },
      data () {
        return {
          languages: lang
          // date: this.propDate // 하위 컴포넌트부터 값이 정해지므로 초기렌더링시 값이 안내려온다
        }
      },
      computed: {
        date: {
          get () {
            console.log('get')
            return this.propDate
          },
          set (newVal) {)
            this.$emit('update:dateSettting', newVal)
          }
        }
      },
      components: {
        Datepicker
      }
    }
    </script>
    

     

    부모가 먼저 생기지만 마운팅 순서는 자식이 먼저이기 때문에 초기 렌더링시 값이 비어있다.

    이러한 이유로 위 코드에서 처럼 자식에 props 데이터를 자식 데이터에 연결해서 쓸때 data() 속성을 사용하지 않고,

    computed 를 통해서 사용해야 한다.

     

    이런 비동기적인 props를 전달받는 상황이라면 computed속성을 사용하는 것이 맞다

     

    참고문헌

    https://kjwsx23.tistory.com/357
    [Vue.js] props로 받은 데이터를 data로 사용하기

    https://stackoverflow.com/questions/45943682/how-to-initialize-data-properties-with-prop-values
    How to Initialize Data Properties with Prop Values

     

    반응형

    댓글

Designed by Tistory.