Vue.js 2에서 소품을 초기 데이터로 전달하는 올바른 방법은 무엇입니까?


97

그래서 나는 Vue 컴포넌트에 props를 전달하고 싶지만, 이러한 props는 예를 들어 AJAX를 사용하여 내부에서 Vue 컴포넌트를 업데이트 할 때 그 컴포넌트 내부에서 미래에 변경 될 것으로 예상합니다. 따라서 구성 요소 초기화에만 사용됩니다.

cars-list초기 속성이있는 소품을 다음 위치에 전달하는 내 Vue 구성 요소 요소 single-car:

// cars-list.vue

<script>
    export default {
        data: function() {
            return {
                cars: [
                    {
                        color: 'red',
                        maxSpeed: 200,
                    },
                    {
                        color: 'blue',
                        maxSpeed: 195,
                    },
                ]
            }
        },
    }
</script>

<template>
    <div>
        <template v-for="car in cars">
            <single-car :initial-properties="car"></single-car>
        </template>
    </div>
</template>

내가 지금 수행하는 방식은 내 single-car구성 요소 this.initialPropertiesthis.data.properties에서 created()초기화 후크 에 할당 하는 것 입니다 . 그리고 그것은 작동하고 반응합니다.

// single-car.vue

<script>
    export default {
        data: function() {
            return {
                properties: {},
            }
        },
        created: function(){
            this.data.properties = this.initialProperties;
        },
    }
</script>

<template>
    <div>Car is in {{properties.color}} and has a max speed of {{properties.maxSpeed}}</div>
</template>

하지만 내 문제는 그것이 올바른 방법인지 모르겠다는 것입니다. 그것은 나에게 길을 따라 약간의 문제를 일으키지 않습니까? 아니면 더 좋은 방법이 있습니까?


13
모든 :이 내 의견에 뷰에 대한 가장 혼동하는 일이 data되어 two-way구속,하지만 당신은 통과 할 수없는 data구성 요소, 당신은 통과 props,하지만 당신은 수신 한 변경할 수 props없으며 변환 propsdata. 그리고 뭐? 제가 배운 한 가지는 전달 props하고 이벤트를 트리거 해야한다는 것입니다. 즉, 컴포넌트가 props수신 한 내용 을 변경하려면 이벤트를 호출하고 "렌더링"해야합니다. 그러나 당신은 one-wayReact와 똑같은 바인딩을 남겼고 나는 data그때에 대한 사용법을 보지 못했습니다 . 꽤 혼란 스럽습니다.
André Pena 2011

1
데이터는 주로 구성 요소를 개인적으로 사용하기위한 것입니다. 구성 요소의 컨텍스트 내에서 배치 된 모든 것은 반응 적이며 바인딩 될 수 있습니다. props의 개념은 구성 요소에 값을 전달하지만 전달 된 값을 변경하여 구성 요소가 부모에 상태 변경을 자동으로 도입 할 수 없도록하는 것입니다. 귀하가 지시 한대로 이벤트에서 명시 적으로 만드는 것이 좋습니다. 이것은 Vue 1.0에서 2.0으로의 철학 변경이었습니다.
David K. Hess 2016

오늘 저는 여기에서 스레드를 시작하려고했습니다 : forum.vuejs.org/t/…
bgraves

답변:


103

https://github.com/vuejs/vuejs.org/pull/567 덕분에 이제 답을 알고 있습니다.

방법 1

초기 소품을 데이터에 직접 전달합니다. 업데이트 된 문서의 예와 같습니다.

props: ['initialCounter'],
data: function () {
    return {
        counter: this.initialCounter
    }
}

그러나 전달 된 소품이 부모 구성 요소 상태에서 사용되는 객체 또는 배열 인 경우 해당 소품을 수정하면 해당 부모 구성 요소 상태가 변경됩니다.

경고 :이 방법은 권장되지 않습니다. 구성 요소를 예측할 수 없게 만듭니다. 하위 구성 요소에서 부모 데이터를 설정해야하는 경우 Vuex와 같은 상태 관리를 사용하거나 "v-model"을 사용합니다. https://vuejs.org/v2/guide/components.html#Using-v-model-on-Components

방법 2

초기 소품이 객체 또는 배열이고 자식 상태의 변경 사항이 부모 상태로 전파되는 것을 원하지 않는 경우 다음 Vue.util.extend과 같이 자식 데이터를 직접 가리키는 대신 예를 들어 [1]을 사용하여 소품의 복사본을 만듭니다.

props: ['initialCounter'],
data: function () {
    return {
        counter: Vue.util.extend({}, this.initialCounter)
    }
}

방법 3

스프레드 연산자를 사용하여 소품을 복제 할 수도 있습니다. Igor 답변에 대한 자세한 내용 : https://stackoverflow.com/a/51911118/3143704

그러나 스프레드 연산자는 이전 브라우저에서 지원되지 않으며 더 나은 호환성을 위해 코드를 변환해야합니다 (예 : babel.

각주

[1] 이것은 내부 Vue 유틸리티이며 새 버전으로 변경 될 수 있습니다. 다른 방법을 사용하여 해당 소품을 복사 할 수 있습니다 . " JavaScript 객체를 올바르게 복제하려면 어떻게해야합니까? "를 참조하십시오.

내가 테스트 한 내 바이올린 : https://jsfiddle.net/sm4kx7p9/3/


1
그래서 부모 구성 요소에 변경 사항을 전파하는 것이 좋습니다.
이고르

1
@igor 개인적으로 나는 당신이 할 수있는 한 그것을 피하려고 노력할 것입니다. 구성 요소를 예측할 수 없게 만듭니다. 부모 구성 요소를 변경하는 더 좋은 방법은 자식 구성 요소에서 부모 구성 요소로 변경 사항을 $ emit하는 "v-model"메서드를 사용하는 것입니다. vuejs.org/v2/guide/components.html#Using-v-model-on-Components
Dominik Serafin

예,하지만 깊은 물체는 어떻습니까? 딥 카피를해야합니까? 딥 오브젝트를 사용하지 않도록 구성 요소를 다시 디자인해야합니까? 즉, 다음과 같은 소품 : { ok: 1, notOk: { meh: 2 } }이전 복제 방법 중 하나를 사용하여 내부 데이터로 설정하면 여전히 소품이 변경됩니다notOk.meh
Nikso

1
@DominikSerafin에 대한 훌륭한 질문과 답변에 감사드립니다. 이것은 Vue.js의 아킬레스 건을 완벽하게 보여줍니다. 프레임 워크로서 구성 요소 화를 매우 잘 처리하지만 구성 요소간에 데이터를 전달하는 것은 주요 PITA입니다. 만들어진 명명법 악몽을보십시오. 이제 initial내 comp 내에서 사용할 수 있도록 모든 props에 접두사를 붙여야합니다 . data어떤 comp에 호출 된 prop 을 전달하고이 모든 initialPropName광기 없이 지역화 된 데이터를 자동으로 전파 할 수 있다면 훨씬 더 깨끗할 것입니다.
AJB

1
@DominikSerafin 나는 당신이 말하는 것을 듣고 당신은 틀리지 않았습니다. 그러나 Vue.js를 사용하여 양식 작성기 앱을 작성하면 내가 의미하는 바를 빠르게 알 수 있습니다. 실제로 데이터 공유 기술 prop --> comp.data모든 데이터에 대해 Vue-Stash 사용 으로 변경하는 중입니다 (또는 Vuex도 작동합니다). 하지만 지금 window은 "현대적인"JS 프레임 워크가 나에게 의견을 제시하기 전에했던 것처럼 데이터를 객체 에서 튕겨 내고 있습니다. 그래서 질문을합니다. comp.data 속성의 요점은 무엇입니까?
AJB

25

@ dominik-serafin의 답변과 함께 :

객체를 전달하는 경우 확산 연산자 (ES6 구문)를 사용하여 쉽게 복제 할 수 있습니다.

 props: {
   record: {
     type: Object,
     required: true
   }
 },

data () { // opt. 1
  return {
    recordLocal: {...this.record}
  }
},

computed: { // opt. 2
  recordLocal () {
    return {...this.record}
  }
},

그러나 가장 중요한 것은 opt를 사용하는 것입니다. 2 계산 된 값을 전달하는 경우 또는 그 이상의 비동기 값을 전달합니다. 그렇지 않으면 로컬 값이 업데이트되지 않습니다.

데모:

Vue.component('card', { 
  template: '#app2',
  props: {
    test1: null,
    test2: null
  },
  data () { // opt. 1
    return {
      test1AsData: {...this.test1}
    }
  },
  computed: { // opt. 2
    test2AsComputed () {
      return {...this.test2}
    }
  }
})

new Vue({
  el: "#app1",
  data () {
    return {
      test1: {1: 'will not update'},
      test2: {2: 'will update after 1 second'}
    }
  },
  mounted () {
    setTimeout(() => {
      this.test1 = {1: 'updated!'}
      this.test2 = {2: 'updated!'}
    }, 1000)
  }
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>

<div id="app1">
  <card :test1="test1" :test2="test2"></card>
</div>

<template id="app2">
  <div>
    test1 as data: {{test1AsData}}
    <hr />
    test2 as computed: {{test2AsComputed}}
  </div>
</template>

https://jsfiddle.net/nomikos3/eywraw8t/281070/


@ igor-parra 님, 중복 된 답변을 제출하신 것 같습니다. 또한 스프레드 연산자가 모든 브라우저에서 지원되는 것은 아니며 더 나은 호환성을 위해 트랜스 파일 단계가 필요할 수 있다는 점도 언급하는 것이 좋습니다. 그렇지 않으면 멋지게 보입니다.이 대체 방법을 추가해 주셔서 감사합니다!
Dominik Serafin

@ dominik-serafin 예, 맞습니다. ES6에 대한 참조를 추가했습니다. 웹팩 기반 애플리케이션에서는 최신 자바 스크립트를 최대한 활용하기 위해 바벨을 미리 구성하는 것이 매우 쉽습니다.
Igor Parra

recordLocal: [...this.record](내 경우 레코드는 배열입니다) vue 구성 요소를로드하고 검사 한 후 record항목을 포함하고 recordLocal빈 배열이었습니다.
Christian

COMPUTED 속성을 사용하더라도 잘 작동합니다. 데이터 내부에 설정하려고하면 작동하지 않습니다. = (...하지만 사용했습니다computed
felipe muner

조심해. 스프레드 연산자는 얕은 복제본 만 사용하므로 개체 또는 배열이 포함 된 개체의 경우 새 복사본을 가져 오는 대신 포인터를 계속 복사합니다. lodash에서 cloneDeep을 사용합니다.
Cindy Conway

13

문서에 명시된 내용이기 때문에 올바르게하고 있다고 생각합니다.

소품의 초기 값을 초기 값으로 사용하는 로컬 데이터 속성을 정의합니다.

https://vuejs.org/guide/components.html#One-Way-Data-Flow


4
값에 의한 전달 소품의 경우 괜찮습니다. 이 경우 개체이므로 변경하면 상위 항목에 영향을줍니다. 해당 페이지에서 : "JavaScript의 객체와 배열은 참조로 전달되므로 소품이 배열 또는 객체 인 경우 자식 구성 요소 내에서 객체 또는 배열 자체를 변경하면 부모 상태에 영향을줍니다."
Jake

이것은 나를 위해 작동하며 명확하게 문서화되어 있습니다. 위 답변의이 줄은 내가 말할 수있는 한 vue 문서와 충돌합니다. "경고 :이 방법은 권장되지 않습니다. 구성 요소를 예측할 수 없게됩니다. 하위 구성 요소에서 부모 데이터를 설정해야하는 경우 Vuex와 같은 상태 관리를 사용하거나 "V 모델". "
나다니엘 스케이트장

그래서 4 년과 수백 시간의 학습 곡선 끝에 저는 바로 window객체에서 vars를 튕기기 시작했던 곳으로 돌아 왔습니다 .
AJB
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.