Vue 2 - 음소거 소품 Vue-warn
저는 https://laracasts.com/series/learning-vue-step-by-step 시리즈를 시작했습니다.다음 오류로 인해 Vue, Laravel 및 AJAX 레슨을 중단했습니다.
vue.js:2574 [Vue warn]:상위 구성 요소가 다시 렌더링될 때마다 값이 덮어쓰므로 프롭을 직접 변환하지 마십시오.대신, 프롭 값을 기반으로 데이터 또는 계산된 속성을 사용합니다.변환 중인 Prop: "list"(구성 요소에서 발견됨)
이 코드는 메인.js에 있습니다.
Vue.component('task', {
template: '#task-template',
props: ['list'],
created() {
this.list = JSON.parse(this.list);
}
});
new Vue({
el: '.container'
})
리스트 프롭을 덮어쓸 때 문제가 생성()된 것은 알지만, 저는 뷰에 처음 와서 수정하는 방법을 전혀 모르겠습니다.수리 방법을 아는 사람이 있습니까? (그리고 이유를 설명해 주십시오)
이는 Vue 2에서 프롭을 로컬로 변형하는 것이 안티패턴으로 간주된다는 사실과 관련이 있습니다.
프롭을 로컬로 변형하려는 경우 지금 해야 할 일은 필드를 선언하는 것입니다.data
을 props
값을 초기 값으로 지정한 다음 복사본을 변환합니다.
Vue.component('task', {
template: '#task-template',
props: ['list'],
data: function () {
return {
mutableList: JSON.parse(this.list);
}
}
});
이에 대한 자세한 내용은 Vue.js 공식 가이드를 참조하십시오.
참고 1: 및 에 동일한 이름을 사용해서는 안 됩니다. 예:
data: function () { return { list: JSON.parse(this.list) } } // WRONG!!
참고 2: 제가 느끼기에 다음과 관련하여 약간의 혼란이 있습니다.props
그리고 반응성, 이 스레드를 한 번 봐보는 것을 제안합니다.
은 Vue 패은입니다.props
아래와 아래로events
사용자 구성 요소를 할 때 . 단순하게 들리지만 사용자 지정 구성 요소를 작성할 때 잊어버리기 쉽습니다.
Vue 2.2.0부터는 v-model(계산된 속성 포함)을 사용할 수 있습니다.이러한 조합을 통해 구성 요소 간에 간단하고 깨끗하고 일관된 인터페이스가 생성됩니다.
- 조금도
props
에 전달된 반응성, 하지 않음)이됩니다.watch
변경 사항이 탐지될 때 로컬 복사본을 업데이트하는 기능). - 변경사항은 자동으로 상위 항목으로 전송됩니다.
- 여러 수준의 성분과 함께 사용할 수 있습니다.
계산된 속성을 사용하면 세터와 게터를 별도로 정의할 수 있습니다.를 통해 이를통을 할 수 있습니다.Task
다음과 같이 다시 작성할 구성 요소:
Vue.component('Task', {
template: '#task-template',
props: ['list'],
model: {
prop: 'list',
event: 'listchange'
},
computed: {
listLocal: {
get: function() {
return this.list
},
set: function(value) {
this.$emit('listchange', value)
}
}
}
})
모델 속성은 다음을 정의합니다.prop
와 관련이 있습니다.v-model
그리고 어떤 이벤트가 변경될 때 방출되는지 확인합니다.그런 다음 부모에서 이 구성 요소를 다음과 같이 호출할 수 있습니다.
<Task v-model="parentList"></Task>
그listLocal
계산된 속성은 구성 요소 내에서 간단한 게터 및 세터 인터페이스를 제공합니다(개인 변수라고 생각).에 내#task-template
렌더링할 수 있습니다.listLocal
그리고 반응성을 유지할 것입니다(즉, 만약에parentList
를 변경하면 됩니다.Task
구성 요소).돌연변이를 일으킬 수도 있습니다.listLocal
세터를 호출함으로써(예:this.listLocal = newList
그러면 변경 내용이 부모에게 전송됩니다.
이 패턴의 좋은 점은 당신이 통과할 수 있다는 것입니다.listLocal
성소에요의 하위 에.Task
((으)로 사용v-model
요소의 사항은 및 하위 구성 요소의 변경 사항이 최상위 구성 요소로 전파됩니다.
예를 들어, 우리가 따로 있다고 칩시다.EditTask
작업 데이터를 수정하기 위한 구성 요소입니다.동일하게 사용함으로써v-model
할 수 .listLocal
)v-model
):
<script type="text/x-template" id="task-template">
<div>
<EditTask v-model="listLocal"></EditTask>
</div>
</script>
한다면EditTask
적절하게 호출할 변화를 방출합니다.set()
listLocal
이벤트를 최상위 수준으로 전파합니다. 가지로찬마,로,EditTask
구요또는다한예사음다요를구하소른성위여호다출수있니할습성용하소요폼소을예)를▁also▁component▁could▁elements▁child▁other를 사용하여 다른 자식 구성요소(예: 폼 요소)를 호출할 수 있습니다.v-model
.
Vue는 구성 요소에서 프롭을 변경하지만 상위 구성 요소가 다시 렌더링되면 "list"가 덮어쓰여 모든 변경 사항을 잃게 됩니다.그래서 그렇게 하는 것은 위험합니다.
대신 다음과 같이 계산된 속성을 사용합니다.
Vue.component('task', {
template: '#task-template',
props: ['list'],
computed: {
listJson: function(){
return JSON.parse(this.list);
}
}
});
Lodash를 사용하는 경우에는 반환하기 전에 소품을 복제할 수 있습니다.이 패턴은 부모와 자식 모두에서 해당 소품을 수정하는 경우 유용합니다.
구성요소 그리드에 대한 제안 목록이 있다고 가정해 보겠습니다.
상위 구성 요소
<grid :list.sync="list"></grid>
하위 구성 요소
props: ['list'],
methods:{
doSomethingOnClick(entry){
let modifiedList = _.clone(this.list)
modifiedList = _.uniq(modifiedList) // Removes duplicates
this.$emit('update:list', modifiedList)
}
}
소품은 내려가고, 이벤트는 위로.그것이 뷰의 패턴입니다.요점은 만약 여러분이 부모로부터 전해지는 소품들을 변형시키려 한다면 말입니다.작동하지 않고 상위 구성 요소에 의해 반복적으로 덮어씁니다.하위 구성 요소는 상위 구성 요소에 무언가를 수행하도록 알리는 이벤트만 내보낼 수 있습니다.이러한 제한이 마음에 들지 않으면 VUEX를 사용할 수 있습니다(사실 이 패턴은 복잡한 구성 요소 구조를 흡수하므로 VUEX를 사용해야 합니다!).
하위 구성요소에서 소품의 값을 변경하면 안 됩니다.정말로 변경해야 할 경우 사용할 수 있습니다..sync
.이것처럼만.
<your-component :list.sync="list"></your-component>
Vue.component('task', {
template: '#task-template',
props: ['list'],
created() {
this.$emit('update:list', JSON.parse(this.list))
}
});
new Vue({
el: '.container'
})
VueJs 2.0에 따르면 구성 요소 내부의 소품을 변형해서는 안 됩니다.그들은 부모님에 의해서만 돌연변이를 당합니다.따라서 이름이 다른 데이터에서 변수를 정의하고 실제 소품을 보고 업데이트해야 합니다.부모에 의해 목록 프롭이 변경된 경우, 이를 구문 분석하여 mutableList에 할당할 수 있습니다.여기 완전한 해결책이 있습니다.
Vue.component('task', {
template: ´<ul>
<li v-for="item in mutableList">
{{item.name}}
</li>
</ul>´,
props: ['list'],
data: function () {
return {
mutableList = JSON.parse(this.list);
}
},
watch:{
list: function(){
this.mutableList = JSON.parse(this.list);
}
}
});
mutableList를 사용하여 템플릿을 렌더링하므로 구성 요소에서 목록 소품을 안전하게 유지할 수 있습니다.
답은 간단합니다. 일부 로컬 구성 요소 변수(게터, 세터 또는 감시자로 계산된 데이터 속성일 수 있음)에 값을 할당하여 직접적인 속성 변환을 해제해야 합니다.
여기 와쳐를 이용한 간단한 해결책이 있습니다.
<template>
<input
v-model="input"
@input="updateInput"
@change="updateInput"
/>
</template>
<script>
export default {
props: {
value: {
type: String,
default: '',
},
},
data() {
return {
input: '',
};
},
watch: {
value: {
handler(after) {
this.input = after;
},
immediate: true,
},
},
methods: {
updateInput() {
this.$emit('input', this.input);
},
},
};
</script>
이것은 제가 데이터 입력 구성 요소를 만드는 데 사용하는 것으로, 잘 작동합니다.부모로부터 전송된 모든 새 데이터(v-model(ed))는 값 감시자에 의해 감시되고 입력 변수에 할당되며, 입력이 수신되면 해당 동작을 포착하여 부모에게 폼 요소에서 데이터가 입력되었음을 암시하는 입력을 보낼 수 있습니다.
구성 요소에서 직접 소품을 변경하지 마십시오. 변경이 필요한 경우 다음과 같이 새 속성을 설정합니다.
data() {
return {
listClone: this.list
}
}
listClone의 값을 변경합니다.
저도 이 문제에 직면했습니다.사용 후 경고가 사라졌습니다.$on
그리고.$emit
그것은 쓸모 있는 것과 같습니다.$on
그리고.$emit
하위 구성 요소에서 상위 구성 요소로 데이터를 보내는 것이 좋습니다.
단방향 데이터 흐름, https://v2.vuejs.org/v2/guide/components.html, 에 따르면 구성 요소는 단방향 데이터 흐름을 따릅니다. 모든 속성은 하위 속성과 상위 속성 사이에 단방향 다운 바인딩을 형성합니다. 상위 속성이 업데이트되면 하위 속성은 하위 속성으로 이동하지만 그 반대는 아닙니다.이렇게 하면 하위 구성 요소가 실수로 상위 구성 요소를 변형하지 못하도록 하여 앱의 데이터 흐름을 이해하기 어렵게 할 수 있습니다.
또한 상위 구성 요소가 업데이트될 때마다 하위 구성 요소의 모든 소품이 최신 값으로 새로 고쳐집니다.즉, 하위 구성 요소 내부의 소품을 변형하지 않아야 합니다.그러면 .vue가 콘솔에서 경고를 표시합니다.
일반적으로 두 가지 경우가 있는데, 다음과 같이 변형할 수 있습니다.초기 값을 전달하는 데 사용되며 하위 구성 요소는 나중에 로컬 데이터 속성으로 사용하려고 합니다.프롭은 변환해야 하는 원시 값으로 전달됩니다.이러한 사용 사례에 대한 올바른 대답은 다음과 같습니다. Prop의 초기 값을 초기 값으로 사용하는 로컬 데이터 속성을 정의하십시오.
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
프롭 값에서 계산되는 계산된 속성을 정의합니다.
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
소품을 변경하려면 객체를 사용합니다.
<component :model="global.price"></component>
구성 요소:
props: ['model'],
methods: {
changeValue: function() {
this.model.value = "new value";
}
}
저는 많은 코드, 감시자 및 계산된 속성을 사용하지 않도록 하는 데 도움이 되는 이 답변을 드리고 싶습니다.경우에 따라 이 방법이 좋은 해결책이 될 수 있습니다.
소품은 단방향 커뮤니케이션을 제공하도록 설계되었습니다.
show/hide
내게 가장 좋은 해결책은 이벤트를 내보내는 것입니다.
<button @click="$emit('close')">Close Modal</button>
그런 다음 수신기를 모달 요소에 추가합니다.
<modal :show="show" @close="show = false"></modal>
(이경우소품소품이show
당신이 쉬운 것을 사용할 수 있기 때문에 아마도 불필요할 것입니다.v-if="show"
베이스 트랙터에 직접 연결)
이렇게 계산된 방법을 추가해야 합니다.
요소.가치관
props: ['list'],
computed: {
listJson: function(){
return JSON.parse(this.list);
}
}
Vue.component('task', {
template: '#task-template',
props: ['list'],
computed: {
middleData() {
return this.list
}
},
watch: {
list(newVal, oldVal) {
console.log(newVal)
this.newList = newVal
}
},
data() {
return {
newList: {}
}
}
});
new Vue({
el: '.container'
})
아마 이것이 당신의 요구를 충족시킬 것입니다.
Vue3는 정말 좋은 솔루션을 가지고 있습니다.그곳에 도착하는 데 몇 시간이 걸렸습니다.하지만 정말 잘 작동했습니다.
상위 템플릿
<user-name
v-model:first-name="firstName"
v-model:last-name="lastName"
></user-name>
하위 구성 요소
app.component('user-name', {
props: {
firstName: String,
lastName: String
},
template: `
<input
type="text"
:value="firstName"
@input="$emit('update:firstName',
$event.target.value)">
<input
type="text"
:value="lastName"
@input="$emit('update:lastName',
$event.target.value)">
`
})
이것이 양방향 바인딩을 하는 유일한 해결책이었습니다.저는 처음 두 개의 답변이 SYNC 및 Emitting 업데이트 이벤트를 사용하고 컴퓨팅 속성을 더 잘 설정할 수 있는 좋은 방법으로 해결된 것을 좋아했지만, 그것은 매우 힘든 일이었고 저는 그렇게 열심히 일하는 것을 좋아하지 않았습니다.
Vue.js 소품은 Vue에서 Anti-Pattern으로 간주되므로 변형되지 않습니다.
사용자가 취해야 할 접근 방식은 목록의 원래 특성을 참조하는 데이터 특성을 구성 요소에 생성하는 것입니다.
props: ['list'],
data: () {
return {
parsedList: JSON.parse(this.list)
}
}
이제 구성 요소로 전달되는 목록 구조가 다음을 통해 참조되고 변형됩니다.data
의 속성 에 대한 설명 :-)
분석하는 것 구성 요소의 ' 목록속구성을분것이작수석상업행의려면하오시사십용'를 하십시오.computed
소품에 좀 더 을 할 수 .이를 통해 소품에 더 깊이 있는 변형을 만들 수 있습니다.
props: ['list'],
computed: {
filteredJSONList: () => {
let parsedList = JSON.parse(this.list)
let filteredList = parsedList.filter(listItem => listItem.active)
console.log(filteredList)
return filteredList
}
}
위의 예제는 목록 프롭을 구문 분석하고 활성 목록-템으로만 필터링한 다음, schnitts 및 kicks에 대해 로그아웃하고 반환합니다.
참고: 둘 다data
&computed
예를 성은템플동참조됩니다게일하서에릿속ced▁in▁the를 참조합니다.
<pre>{{parsedList}}</pre>
<pre>{{filteredJSONList}}</pre>
그것은 쉽게 생각할 수 있습니다.computed
속성(메소드)은 ...라고 불러야 합니다.그렇지 않습니다
TypeScript가 선호하는 개발 언어인 경우
<template>
<span class="someClassName">
{{feesInLocale}}
</span>
</template>
@Prop({default: 0}) fees: any;
// computed are declared with get before a function
get feesInLocale() {
return this.fees;
}
그리고 아닌
<template>
<span class="someClassName">
{{feesInLocale}}
</span>
</template>
@Prop() fees: any = 0;
get feesInLocale() {
return this.fees;
}
새 변수에 소품을 할당합니다.
data () {
return {
listClone: this.list
}
}
최고의 대답에 더해,
Vue.component('task', {
template: '#task-template',
props: ['list'],
data: function () {
return {
mutableList: JSON.parse(this.list);
}
}
});
어레이별로 프롭을 설정하는 것은 개발/프로파일링을 위한 것입니다. 프로덕션에서 프롭 유형을 설정해야 합니다(https://v2.vuejs.org/v2/guide/components-props.html) . 부모가 프롭을 채우지 않은 경우 기본값을 설정해야 합니다.
Vue.component('task', {
template: '#task-template',
props: {
list: {
type: String,
default() {
return '{}'
}
}
},
data: function () {
return {
mutableList: JSON.parse(this.list);
}
}
});
이런 식으로 적어도 빈 물체를 얻을 수 있습니다.mutableList
정의되지 않은 경우 JSON.parse 오류 대신 사용합니다.
예! vue2의 특성을 변환하는 것은 반패턴입니다. 하지만...
다른 규칙을 사용하여 규칙을 어기고 앞으로 나아가세요!당신이 필요한 것은 추가하는 것입니다..sync
상위 범위의 구성 요소 특성에 대한 한정자입니다.
<your-awesome-components :custom-attribute-as-prob.sync="value" />
아래는 스낵바 구성 요소입니다. 이렇게 스낵바 변수를 v-model에 직접 지정하면 작동하지만 콘솔에서 다음과 같은 오류가 발생합니다.
상위 구성 요소가 다시 렌더링될 때마다 값이 덮어쓰므로 프롭을 직접 변환하지 마십시오.대신, 프롭 값을 기반으로 데이터 또는 계산된 속성을 사용합니다.
<template>
<v-snackbar v-model="snackbar">
{{ text }}
</v-snackbar>
</template>
<script>
export default {
name: "loader",
props: {
snackbar: {type: Boolean, required: true},
text: {type: String, required: false, default: ""},
},
}
</script>
이 돌연변이 오류를 제거하는 올바른 방법은 감시자를 사용하는 것입니다.
<template>
<v-snackbar v-model="snackbarData">
{{ text }}
</v-snackbar>
</template>
<script>
/* eslint-disable */
export default {
name: "loader",
data: () => ({
snackbarData:false,
}),
props: {
snackbar: {type: Boolean, required: true},
text: {type: String, required: false, default: ""},
},
watch: {
snackbar: function(newVal, oldVal) {
this.snackbarData=!this.snackbarDatanewVal;
}
}
}
</script>
따라서 이 스낵바를 로드할 주요 구성 요소에서 이 코드를 수행할 수 있습니다.
<loader :snackbar="snackbarFlag" :text="snackText"></loader>
효과적인 솔루션
Vue.js는 이를 안티패턴으로 간주합니다.예를 들어, 선언하고 다음과 같은 몇 가지 소품을 설정합니다.
this.propsVal = 'new Props Value'
따라서 이 문제를 해결하려면 다음과 같은 Vue 인스턴스의 계산된 속성 또는 데이터에 대한 속성 값을 입력해야 합니다.
props: ['propsVal'],
data: function() {
return {
propVal: this.propsVal
};
},
methods: {
...
}
이것은 분명히 효과가 있을 것입니다.
위의 내용 외에도 다음과 같은 문제가 있는 다른 사용자의 경우:
되지 않으면, 는 "props 값필지않아항반상환않전반데다환됩니가이터된달"를 반환합니다.undefined
(공백 대신)."엉망이 될 수도 있습니다.<select>
기본값, 값이 설정되어 있는지 확인하여 해결했습니다.beforeMount()
(설정하지 않은 경우) 다음과 같이 설정합니다.
JS:
export default {
name: 'user_register',
data: () => ({
oldDobMonthMutated: this.oldDobMonth,
}),
props: [
'oldDobMonth',
'dobMonths', //Used for the select loop
],
beforeMount() {
if (!this.oldDobMonth) {
this.oldDobMonthMutated = '';
} else {
this.oldDobMonthMutated = this.oldDobMonth
}
}
}
HTML:
<select v-model="oldDobMonthMutated" id="dob_months" name="dob_month">
<option selected="selected" disabled="disabled" hidden="hidden" value="">
Select Month
</option>
<option v-for="dobMonth in dobMonths"
:key="dobMonth.dob_month_slug"
:value="dobMonth.dob_month_slug">
{{ dobMonth.dob_month_name }}
</option>
</select>
저는 개인적으로 만약 여러분이 소품들을 변형시킬 필요가 있다면 항상 제안합니다. 먼저 그것들을 계산된 속성으로 전달하고 거기서 돌아오면, 그 후에 여러분이 소품들을 쉽게 변형시킬 수 있습니다. 심지어 여러분이 그것들이 다른 구성 요소로부터 변형되거나 우리가 볼 수 있다면, 여러분이 그것들을 추적할 수 있습니다.
Vue praps는 단방향 데이터 흐름이기 때문에 하위 구성 요소가 실수로 상위 상태를 변형하지 않도록 방지합니다.
우리는 Vue 공식 문서에서 이 문제를 해결하기 위한 두 가지 방법을 찾을 것입니다.
하위 구성 요소가 로컬 데이터로 소품을 사용하려면 로컬 데이터 속성을 정의하는 것이 가장 좋습니다.
props: ['list'], data: function() { return { localList: JSON.parse(this.list); } }
프롭은 변환해야 하는 원시 값으로 전달됩니다.이 경우에는 프롭의 값을 사용하여 계산된 속성을 정의하는 것이 가장 좋습니다.
props: ['list'], computed: { localList: function() { return JSON.parse(this.list); }, //eg: if you want to filter this list validList: function() { return this.list.filter(product => product.isValid === true) } //...whatever to transform the list }
항상 vue 또는 다른 프레임워크에서 소품을 변형하지 않도록 해야 합니다.다른 변수에 복사하는 방법을 사용할 수 있습니다.
예를들면. // instead of replacing the value of this.list use a different variable
this.new_data_variable = JSON.parse(this.list)
이에 대한 잠재적인 해결책은 글로벌 변수를 사용하는 것입니다.
import { Vue } from "nuxt-property-decorator";
export const globalStore = new Vue({
data: {
list: [],
},
}
export function setupGlobalsStore() {
Vue.prototype.$globals = globalStore;
}
그런 다음 다음을 사용합니다.
$globals.list
돌연변이를 일으키거나 제시해야 하는 곳이라면 어디든.
언급URL : https://stackoverflow.com/questions/39868963/vue-2-mutating-props-vue-warn
'programing' 카테고리의 다른 글
하위 프로세스 호출에서 종료 코드 및 stderr 가져오기 (0) | 2023.05.31 |
---|---|
NSZombie란 무엇입니까? (0) | 2023.05.31 |
RVM: gemset의 모든 gem 제거 (0) | 2023.05.31 |
Android에서 활동이 시작될 때 EditText가 집중되지 않도록 하는 방법은 무엇입니까? (0) | 2023.05.31 |
Xcode6: 시뮬레이터의 두 인스턴스 실행 (0) | 2023.05.31 |