Vue에서의 반응성
게시 됨: 2022-03-10이 기사에서는 Vue의 반응성, 작동 방식, 새로 생성된 메서드와 함수를 사용하여 반응성 변수를 생성하는 방법을 살펴보겠습니다. 이 기사는 Vue 2.x의 작동 방식을 잘 이해하고 있고 새로운 Vue 3에 익숙해지려는 개발자를 대상으로 합니다.
우리는 이 주제를 더 잘 이해할 수 있도록 간단한 애플리케이션을 만들 것입니다. 이 앱의 코드는 GitHub에서 찾을 수 있습니다.
기본적으로 JavaScript는 반응하지 않습니다 . 이것은 변수 boy
를 생성하고 애플리케이션의 파트 A에서 참조한 다음 파트 B의 boy
수정을 진행하면 파트 A가 boy
의 새 값으로 업데이트되지 않음을 의미합니다.
let framework = 'Vue'; let sentence = `${framework} is awesome`; console.log(sentence) // logs "Vue is awesome" framework = 'React'; console.log(sentence) //should log "React is awesome" if 'sentence' is reactive.
위의 스니펫은 JavaScript의 비반응성 특성을 보여주는 완벽한 예입니다. 따라서 변경 사항이 sentence
변수에 반영되지 않는 이유는 무엇입니까?
Vue 2.x에서 props
, computed
및 data()
는 기본적으로 모두 반응형이었습니다. 단, 이러한 구성 요소가 생성될 때 data
에 없는 속성은 예외였습니다. 즉, 구성 요소가 DOM에 주입될 때 구성 요소의 data
개체에 있는 기존 속성만 해당 속성이 변경되면 구성 요소가 업데이트되도록 합니다.
내부적으로 Vue 3은 Proxy
객체(ECMAScript 6 기능)를 사용하여 이러한 속성이 반응적임을 확인하지만 Internet Explorer 지원(ECMAScript 5)을 위해 Vue 2의 Object.defineProperty
를 사용하는 옵션을 계속 제공합니다. 이 메서드는 개체에 직접 새 속성을 정의하거나 개체의 기존 속성을 수정하고 개체를 반환합니다.
언뜻 보기에 우리 대부분은 반응성이 Vue에서 새로운 것이 아니라는 것을 이미 알고 있기 때문에 이러한 속성을 사용하는 것이 불필요해 보일 수 있지만 여러 곳에서 재사용 가능한 기능이 있는 대규모 응용 프로그램을 처리할 때 Options API에는 한계가 있습니다. 응용 프로그램의 일부. 이를 위해 코드 기반을 더 쉽게 읽고 유지 관리할 수 있도록 논리를 추상화하는 데 도움이 되는 새로운 구성 API가 도입되었습니다. 또한 새로운 속성과 메서드를 사용하여 데이터 유형에 관계없이 모든 변수를 쉽게 반응형으로 만들 수 있습니다.
구성 API의 진입점 역할을 하는 setup
옵션을 사용할 때 setup
이 실행될 때 구성 요소 인스턴스가 아직 생성되지 않았기 때문에 data
개체, computed
된 속성 및 methods
에 액세스할 수 없습니다. 이로 인해 setup
에서 이러한 기능의 기본 제공 반응성 을 활용하는 것이 불가능합니다. 이 튜토리얼에서 우리는 이것을 할 수 있는 모든 방법에 대해 배울 것입니다.
반응적 방법
문서에 따르면 Vue 2.6의 Vue.observable()
에 해당하는 reactive
메서드는 모든 속성이 반응성인 객체(예: Options의 data
객체)를 만들려고 할 때 유용할 수 있습니다. API). 내부적으로 Options API의 data
개체는 이 메서드를 사용하여 모든 속성을 반응형으로 만듭니다.
하지만 우리는 다음과 같이 반응형 객체를 생성할 수 있습니다.
import { reactive } from 'vue' // reactive state let user = reactive({ "id": 1, "name": "Leanne Graham", "username": "Bret", "email": "[email protected]", "address": { "street": "Kulas Light", "suite": "Apt. 556", "city": "Gwenborough", "zipcode": "92998-3874", "geo": { "lat": "-37.3159", "lng": "81.1496" } }, "phone": "1-770-736-8031 x56442", "website": "hildegard.org", "company": { "name": "Romaguera-Crona", "catchPhrase": "Multi-layered client-server neural-net", "bs": "harness real-time e-markets" }, "cars": { "number": 0 } })
여기에서 Vue에서 reactive
메서드를 가져온 다음 이 함수에 인수로 값을 전달하여 user
변수를 선언했습니다. 그렇게 함으로써 user
를 반응형으로 만들었습니다. 따라서 템플릿에서 user
를 사용하고 이 개체의 개체 또는 속성이 변경되어야 하는 경우 이 값은 이 템플릿에서 자동으로 업데이트됩니다.
ref
객체를 반응형으로 만드는 방법이 있는 것처럼 다른 독립형 기본 값 (문자열, 부울, 정의되지 않은 값, 숫자 등)과 배열을 반응형으로 만드는 방법도 필요합니다. 개발하는 동안 우리는 이러한 다른 데이터 유형을 사용하면서 반응형 데이터도 필요로 했습니다. 우리가 생각할 수 있는 첫 번째 접근 방식은 반응형을 사용하고 reactive
형으로 만들 변수의 값을 전달하는 것입니다.
import { reactive } from 'vue' const state = reactive({ users: [], });
reactive
은 반응형 변환이 심하기 때문에 속성으로서의 user
도 반응형이므로 목표를 달성할 수 있습니다. 따라서 user
는 이러한 앱의 템플릿에서 사용되는 모든 위치에서 항상 업데이트합니다. 그러나 ref
속성을 사용하면 해당 변수의 값을 ref
에 전달하여 모든 데이터 유형의 변수를 반응형으로 만들 수 있습니다. 이 방법은 개체에도 적용되지만 reactive
방법을 사용할 때보다 한 단계 더 깊이 개체를 중첩합니다.
let property = { rooms: '4 rooms', garage: true, swimmingPool: false } let reactiveProperty = ref(property) console.log(reactiveProperty) // prints { // value: {rooms: "4 rooms", garage: true, swimmingPool: false} // }
내부적으로 ref
는 전달된 이 인수를 받아 value
키가 있는 객체로 변환합니다. 즉, variable.value 를 호출하여 variable.value
에 액세스할 수 있으며 같은 방식으로 호출하여 해당 값을 수정할 수도 있습니다.
import {ref} from 'vue' let age = ref(1) console.log(age.value) //prints 1 age.value++ console.log(age.value) //prints 2
이를 통해 ref
를 구성 요소로 가져오고 반응 변수를 만들 수 있습니다.
<template> <div class="home"> <form @click.prevent=""> <table> <tr> <th>Name</th> <th>Username</th> <th>email</th> <th>Edit Cars</th> <th>Cars</th> </tr> <tr v-for="user in users" :key="user.id"> <td>{{ user.name }}</td> <td>{{ user.username }}</td> <td>{{ user.email }}</td> <td> <input type="number" name="cars" v-model.number="user.cars.number" /> </td> <td> <cars-number :cars="user.cars" /> </td> </tr> </table> <p>Total number of cars: {{ getTotalCars }}</p> </form> </div> </template> <script> // @ is an alias to /src import carsNumber from "@/components/cars-number.vue"; import axios from "axios"; import { ref } from "vue"; export default { name: "Home", data() { return {}; }, setup() { let users = ref([]); const getUsers = async () => { let { data } = await axios({ url: "data.json", }); users.value = data; }; return { users, getUsers, }; }, components: { carsNumber, }, created() { this.getUsers(); }, computed: { getTotalCars() { let users = this.users; let totalCars = users.reduce(function(sum, elem) { return sum + elem.cars.number; }, 0); return totalCars; }, }; </script>
여기에서 컴포넌트에 반응적인 users
변수를 생성하기 위해 ref
를 가져왔습니다. 그런 다음 public
폴더의 JSON 파일에서 데이터를 가져오기 위해 axios
를 가져왔고, 나중에 생성할 carsNumber
구성 요소를 가져왔습니다. 다음으로 수행한 작업은 ref
메서드를 사용하여 반응형 users
변수를 생성하여 users
가 JSON 파일의 응답이 변경될 때마다 업데이트할 수 있도록 하는 것입니다.
또한 axios를 사용하여 JSON 파일에서 users
배열을 가져오는 getUser
함수를 만들고 이 요청의 값을 users
변수에 할당했습니다. 마지막으로 템플릿 섹션에서 수정한 대로 사용자가 소유한 총 자동차 수를 계산하는 계산된 속성을 만들었습니다.
템플릿 섹션 또는 setup()
외부에서 반환된 ref
속성에 액세스할 때 자동으로 얕은 래핑 해제된다는 점에 유의하는 것이 중요합니다. 이는 객체인 refs
에 액세스하기 위해 여전히 .value
가 필요하다는 것을 의미합니다. users
는 배열이기 때문에 getTotalCars
에서 users.value
가 아닌 users
를 사용할 수 있습니다.
템플릿 섹션에서는 <cars-number />
컴포넌트와 함께 각 사용자의 정보를 표시하는 테이블을 표시했습니다. 이 구성 요소는 각 사용자의 행에 표시되는 cars
소품을 소유한 자동차 수로 받아들입니다. 이 값 은 사용자 개체에서 cars
값이 변경될 때마다 업데이트됩니다. 이는 Options API로 작업하는 경우 data
개체 또는 computed
된 속성이 작동하는 방식과 동일합니다.
toRefs
구성 API를 사용할 때 setup
함수는 props
및 context
의 두 인수를 허용합니다. 이 props
는 구성 요소에서 setup()
으로 전달되며, 이를 통해 이 새 API 내부에서 구성 요소가 가지고 있는 props에 액세스할 수 있습니다. 이 방법은 반응성을 잃지 않고 객체 를 구조화할 수 있기 때문에 특히 유용합니다.
<template> <p>{{ cars.number }}</p> </template> <script> export default { props: { cars: { type: Object, required: true, }, gender: { type: String, required: true, }, }, setup(props) { console.log(props); // prints {gender: "female", cars: Proxy} }, }; </script> <style></style>
컴포지션 API에서 props
의 객체인 값을 사용하면서 반응성을 유지하려면 toRefs
를 사용합니다. 이 메서드는 반응 객체를 가져와 원래 반응 객체의 각 속성이 ref
가 되는 일반 객체로 변환합니다. 이것이 의미하는 바는 cars
가 지지한다는 것입니다...
cars: { number: 0 }
... 이제 다음과 같이 됩니다.
{ value: cars: { number: 0 }
이를 통해 반응성을 유지하면서 설정 API의 모든 부분 내에서 cars
를 사용할 수 있습니다.
setup(props) { let { cars } = toRefs(props); console.log(cars.value); // prints {number: 0} },
우리는 합성 API의 watch
를 사용하여 이 새로운 변수를 감시하고 우리가 원하는 대로 이 변경에 반응할 수 있습니다.
setup(props) { let { cars } = toRefs(props); watch( () => cars, (cars, prevCars) => { console.log("deep ", cars.value, prevCars.value); }, { deep: true } ); }
toRef
우리가 직면할 수 있는 또 다른 일반적인 사용 사례는 반드시 객체가 아니라 ref
(배열, 숫자, 문자열, 부울 등)와 함께 작동하는 데이터 유형 중 하나인 값을 전달하는 것입니다. toRef
를 사용하면 소스 반응 객체에서 반응 속성(예: ref
)을 만들 수 있습니다. 이렇게 하면 속성이 반응 상태를 유지하고 상위 소스가 변경될 때마다 업데이트됩니다.
const cars = reactive({ Toyota: 1, Honda: 0 }) const NumberOfHondas = toRef(state, 'Honda') NumberOfHondas.value++ console.log(state.Honda) // 1 state.Honda++ console.log(NumberOfHondas.value) // 2
여기에서는 Toyota
및 Honda
속성을 사용하여 reactive
방법을 사용하여 반응 개체를 만들었습니다. 우리는 또한 Honda
에서 반응 변수를 생성하기 위해 toRef
를 사용했습니다. 위의 예에서 우리는 리액티브 cars
객체 또는 NumberOfHondas
를 사용하여 Honda
를 업데이트할 때 값이 두 인스턴스 모두에서 업데이트됨을 알 수 있습니다.
이 메서드는 소스에 대한 연결을 유지하고 문자열, 배열 및 숫자에 사용할 수 있다는 점에서 위에서 다룬 toRefs
메서드와 유사하지만 매우 다릅니다. toRefs
와 달리 생성 시 해당 속성의 존재에 대해 걱정할 필요가 없습니다. 이 속성이 이 ref
가 생성될 당시 존재하지 않고 대신 null
을 반환하면 여전히 저장되기 때문입니다. 이 값이 변경될 때 toRef
를 사용하여 생성된 이 ref
도 업데이트되도록 watcher
형식이 배치된 유효한 속성입니다.
이 방법을 사용하여 props
에서 반응 속성 을 만들 수도 있습니다. 그것은 다음과 같이 보일 것입니다:
<template> <p>{{ cars.number }}</p> </template> <script> import { watch, toRefs, toRef } from "vue"; export default { props: { cars: { type: Object, required: true, }, gender: { type: String, required: true, }, }, setup(props) { let { cars } = toRefs(props); let gender = toRef(props, "gender"); console.log(gender.value); watch( () => cars, (cars, prevCars) => { console.log("deep ", cars.value, prevCars.value); }, { deep: true } ); }, }; </script>
여기에서 props
에서 가져온 gender
속성을 기반으로 하는 ref
를 만들었습니다. 이것은 특정 구성 요소의 소품에 대해 추가 작업을 수행하려는 경우에 유용합니다.
결론
이 기사에서 우리는 Vue 3에서 새로 도입된 몇 가지 방법과 기능을 사용하여 Vue의 반응성이 어떻게 작동하는지 살펴보았습니다. 우리는 반응성이 무엇인지 그리고 Vue가 이를 달성하기 위해 무대 뒤에서 Proxy
객체를 사용하는 방법을 살펴보는 것으로 시작했습니다. 또한 react를 사용하여 reactive
객체를 생성하는 방법과 ref
를 사용하여 반응 속성을 생성하는 방법을 살펴보았습니다.
마지막으로 리액티브 객체를 일반 객체로 변환하는 방법을 살펴보았습니다. 각각의 속성은 원본 객체의 해당 속성을 가리키는 ref
이며, 리액티브 소스 객체의 속성에 대한 ref
를 만드는 방법을 살펴보았습니다.
추가 리소스
- "프록시"(객체), MDN 웹 문서
- "반응성 기초", Vue.js
- "참조", Vue.js
- “Lifecycle Hook Registration Inside
setup
”, Vue.js