Estoy escribiendo una aplicación en vuejs y quiero pasar prop a un componente secundario, pero recibo este error:
Obtener un valor de los
propsen el ámbito raíz desetup()hará que el valor pierda reactividad
Componente principal
<template> <div> <course-list :courseId = "id" /> </div> </template> import {useRoute} from 'vue-router'; import { ref, onMounted, reactive} from 'vue'; export default defineComponent({ components: { NavBar, CourseList, CourseContent }, props:{ courseId: String }, setup(){ const route = useRoute() const id = route.params.id console.log("the course id is", id); return{ id } } }Componente hijo
export default defineComponent({ components: { CourseTopic }, props: { courseId: { type: String } }, setup(props) { const trainingCourseId = props.courseId; return { courses, trainingCourseId }; }, });¿Cómo soluciono este problema?
Use toRefs() en props para mantener la reactividad en el accesorio:
import { toRefs } from 'vue' export default { setup(props) { const { courseId: trainingCourseId } = toRefs(props) return { trainingCourseId } } } O toRef() :
import { toRef } from 'vue' export default { setup(props) { const trainingCourseId = toRef(props, 'courseId') return { trainingCourseId } } }const trainingCourseId = props.courseId; Todo lo que dice es que su trainingCourseId no es reactivo.
Supongo que el código que publicaste es solo para demostración, porque en este caso específico, en realidad puedes usar el identificador de courseId (en tu plantilla) directamente, y será reactivo.
Sin embargo, la pregunta más importante sigue siendo: ¿por qué courseId es reactivo pero trainingCourseId no lo es? ¿No dice el doctor que los accesorios son un objeto reactivo? ¿Cómo se destruye exactamente la reactividad aquí?
Para que quede claro, reasignar una propiedad a una variable local no siempre elimina toda la reactividad (sí, siempre se perderá algo de reactividad, pero dependiendo de la forma de la propiedad, la pérdida de reactividad puede no ser tan obvia inicialmente) .
Vue 3 usa Proxy para lograr reactividad. La idea es que para el objeto de datos sin procesar dado: { courseId: "something" } , Vue crea otro objeto Proxy que se parece al objeto de datos dado pero con todos los captadores y definidores de propiedades interceptados . La reactividad proviene de estos getters y setters interceptados y, por lo tanto, está asociada con el objeto que posee los getters y setters, no con la propiedad en sí.
En otras palabras:
const raw = { courseId: "something" }; const rxData = reactive(raw); Lo que es reactivo es rxData, no el ID de curso, lo que significa que cualquier acceso a las propiedades de rxData (cualquier propiedad, no tiene que ser ID de curso) es reactivo. Sin embargo, cuando hace const trainingCourseId = rxData.courseId , trainingCourseId no es un proxy, es solo una cadena (recuperada de un proxy).
Esto es un poco diferente cuando CourseId no es una cadena simple sino un objeto:
const raw = { courseId: { name: "something" } }; const rxData = reactive(raw); const trainingCourseId = rxData.courseId; Al construir el proxy reactivo, Vue convierte recursivamente el objeto de datos sin procesar original. Por lo tanto, rxData.courseId es también un Proxy en este caso. Si cambia el nombre del ID del curso por rxData.courseId.name = "something else" , el cambio se reflejará en el ID del curso de capacitación. Sin embargo, si reasigna rxData.courseId por rxData.courseId = { name: "something else" } , esta reasignación no será visible para trainingCourseId.
El método toRef y toRefs mencionado en la otra respuesta te ayudará a deshacerte de todos estos comportamientos divertidos. Pero si está interesado, puede consultar esta pregunta sobre la reactividad de vue3