Однонаправленный поток данных

Последнее обновление: 03.11.2020

При использовании props в компонентах следует учитывать, что данные в props представляют однонаправленный поток данных от родительского компонента к дочерним компонентам. Изменение свойства родителя приведет к изменению в дочерних компонентах. Однако дочерние компоненты не могут изменить свойство родителя. То есть поток данных идет только в одном направлении: родителя к потомкам. Props представяют свойства, доступные только для чтения.

Более того при любом обновлении родительского компонента у дочерних компонентов обновляются значения, передаваемые через props. При обратной ситуации, если мы попробуем изменить в дочерних компонентах значения, переданные через props, то на консоль браузера будет выведено предупреждение о том, что это не следует делать, а сами значения никак не изменятся. Например, рассмотрим следующую ситуацию:

<!DOCTYPE html>
<html>
<head>
<title>Компоненты Vue 3</title>
<meta charset="utf-8" />
</head>
<body>
<div id="app">
    <h2>Hello, {{name}}</h2>
    <user-edit :user="name"></user-edit>
</div>
<script src="https://unpkg.com/vue"></script>
<script>
const app = Vue.createApp({
	data(){
		return {  name: 'Tom' }
	}
});

app.component('user-edit', {
    props: ["user"],
    template: '<div><input type="text" v-model="user" /><p>Name: {{user}}</p></div>'
});
app.mount('#app');
</script>
</body>
</html>

Из родителя - объекта приложения Vue в компонент user-edit через props передается значение name. В этом компоненте мы можем попробовать управлять переданным значением через поле ввода и механизм двусторонней привязки:

<input type="text" v-model="user" />

Но если мы попробуем изменить через поле ввода данное значение, то оно изменится только в рамках компонента user-edit, а на консоль будет выведено предупреждение:

Mutating props in Vue 3

Однако могут быть ситуации, когда нам все таки нужно изменить значения в props. Что делать в этом случае? В этом случае мы можем определить локальную переменную. Через props устанавливается ее начальное значение, и затем компонент работает только с этой переменной:

<!DOCTYPE html>
<html>
<head>
<title>Компоненты Vue 3</title>
<meta charset="utf-8" />
</head>
<body>
<div id="app">
    <h2>Hello, {{name}}</h2>
    <user-edit :user="name"></useredit>
</div>
<script src="https://unpkg.com/vue"></script>
<script>
const app = Vue.createApp({
	data(){
		return {  name: 'Tom' }
	}
});

app.component('user-edit', {
    props: ["user"],
    data() {
      return { userName: this.user}
    },
    template: '<div><input type="text" v-model="userName" /><p>Name: {{userName}}</p></div>'
});
app.mount('#app');
</script>
</body>
</html>

Теперь все действия будут идти с локальной переменной userName. Значения из props в компоненте не будут изменяться, а изменения в родительском компоненте никак не повлияют на значение переменной userName.

Изменение значений из props в компонентах во Vue 3

Синхронизация значений родительского и дочернего компонентов

Предложенное выше решение позволяет изменять внутри компонента данные, полученные от родительского компонента. Но тогда мы можем столкнуться с другой проблемой - а что, если родительский компонент также изменит данные:

<!DOCTYPE html>
<html>
<head>
<title>Компоненты Vue 3</title>
<meta charset="utf-8" />
</head>
<body>
<div id="app">
    <div><h3>Vue App</h3><input type="text" v-model="name" /><p>Hello {{name}}</p></div>
    <user-edit :user="name"></useredit>
</div>
<script src="https://unpkg.com/vue"></script>
<script>
const app = Vue.createApp({
    data(){
        return {  name: 'Tom' }
    }
});
 
app.component('user-edit', {
    props: ["user"],
    data() {
      return { userName: this.user}
    },
    template: '<div><h3>Component</h3><input type="text" v-model="userName" /><p>User name: {{userName}}</p></div>'
});
app.mount('#app');
</script>
</body>
</html>

В данном случае при измнении в родительском компоненте в дочерний компоненте по прежнему изменяется свойство "user" из props. Однако привязка элементов интерфейса идет не к свойству user из props, а к свойству userName из data. Поэтому компонент визуально никак не отразит изменения в родительском компоненте:

Изменение значений из props в родительском компоненте во Vue 3

Что делать в этом случае? В этом случае мы можем отслеживать изменение user из props и соответственно обновлять свойство userName:

app.component('user-edit', {
    props: ["user"],
    data() {
      return { userName: this.user}
    },
	watch: { 
        user(newVal) {
          this.userName = newVal;
        }
    },
    template: '<div><h3>Component</h3><input type="text" v-model="userName" /><p>User name: {{userName}}</p></div>'
});

Теперь с помощью параметра watch определяется наблюдаемое свойство, которое называется также, как и отслеживаемое свойство user из props. Параметр newVal представляет новое значение, которое мы можем присвоить свойству userName и таким образом синхронизировать дочерний компонент с родительским.

Обновление данных props во Vue 3
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850