Me di cuenta de que en Vue podía cambiar los campos de objeto pasados como Props, y cambia estos campos en padre.
¿Es esta una mala técnica? ¿Debe evitarse o puede utilizarse? ¿Cuáles son las advertencias de este enfoque?
Ejemplo:
Parent.vue:
<script setup> import { reactive } from 'vue'; import ChildInput from "./Child.vue"; </script> <script> const myObj = reactive({'val':'Default text'}); </script> <template> <ChildInput :passedObj="myObj" /> <div> It's a parent input: <input v-model="myObj.val"> </div> </template>Niño.vue:
<script setup> const props = defineProps({ passedObj: { type: Object, required: true, }, }) const dropValue = function() { props.passedObj.val = "Changed text"; } </script> <template> <div> <label> It's a child input: <input v-model="passedObj.val"> <button @click="dropValue">Change text</button> </label> </div> </template>Puedes consultar este ejemplo aquí .
La mutación superficial de accesorios está prohibida porque el objeto de accesorios es de solo lectura.
La mutación profunda de prop es una mala práctica que debe evitarse . Una de las razones es que esto hace que el flujo de datos sea más complicado y difícil de seguir, que esto sucedió inconscientemente en este caso explica por qué esto es un problema. Otra posible razón es que el rendimiento puede verse afectado potencialmente porque este escenario se encuentra fuera del uso común, aunque no estoy al tanto de tales problemas de optimización a partir de ahora.
La recomendación oficial es usar el enlace bidireccional v-model cuando los accesorios necesitan mutarse, de modo que la mutación ocurra en el componente principal y se pueda rastrear a través de eventos Vue cuando se necesite depuración. Cuando un accesorio está profundamente mutado, se clona en un niño y se emite a un padre.
Así que parece que es una mala práctica. Dejaré una alternativa que uso yo mismo, si alguien necesita uno escrito con la API de composición.
Si desea modificar solo ciertos campos de una propiedad, puede usar la variable calculada con setter y getter. Como esto.
en padre:
<script setup> import { reactive } from "vue"; import InteractiveTable from "./Child.vue"; // Reactive object, which contains our data const myObj = reactive({ data: [{name: "Sasha", address: "Middle of nowhere"}] }); </script> <InteractiveTable v-model="myObj" /> Recuerde que puede pasar varios v-model con títulos personalizados: v-model:title . En su lugar, también puede escuchar los eventos usted mismo. Como eso:
<InteractiveTable :passedObj="myObj" @update:passedObj="(data) => <something>" />
En niño:
import { computed } from "vue"; // Defining our props // For v-model default prop is 'modelValue' // Don't forget to assign it to a variable const props = defineProps({ modelValue: { type: Object, required: true, }, }); // Emits must be assigned to a variable too const emit = defineEmits([ "update:modelValue", ]); // our computed variable, which we will use in JS instead of prop const localData = computed({ get() { // note that we can use object itself or any of its properties, 'data' in this case return props.modelValue.data; }, set(val) { emit("update:modelValue.data", val); }, });Ahora puedes hacer:
const addRow = function (name, address) { // You have to call this localData with .value // In all other regards you can treat it as a normal variable localData.value.push({ 'name': name, 'address': address, }); }; Puede leer más sobre las variables computed aquí y sobre emit aquí .
Soy bastante nuevo en Vue.js, así que si nota algo mal en mi código, notifíquemelo en los comentarios.