> 웹 프론트엔드 > JS 튜토리얼 > Vue에서 v-model과 함께 객체를 사용하는 방법

Vue에서 v-model과 함께 객체를 사용하는 방법

Susan Sarandon
풀어 주다: 2025-01-20 02:34:39
원래의
395명이 탐색했습니다.

How to use an object with v-model in Vue

구성 요소 간 양방향 데이터 바인딩을 구현하는 Vue.js의 v-model 지시문은 누구나 잘 알고 있습니다. 그러나 사용자 정의 구성 요소에 대해 v-model을 수동으로 구현할 때 일반적으로 몇 가지 문제가 발생합니다.

일반적인 접근 방식은 다음과 같습니다.

<code class="language-javascript">const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
<template></template></code>
로그인 후 복사
로그인 후 복사

컴포넌트 내부의 modelValue prop 값은 수정하지 않습니다. 대신 emit 메서드를 통해 업데이트된 값을 상위 구성 요소에 다시 전달하고 상위 구성 요소가 실제 수정을 수행합니다. 그 이유는 하위 구성 요소가 상위 구성 요소의 상태에 영향을 주어서는 안 되며 데이터 흐름을 복잡하게 만들고 디버깅을 어렵게 만들기 때문입니다.

Vue 문서에 명시된 대로 하위 구성 요소 내에서 소품을 수정해서는 안 됩니다. 이렇게 하면 Vue가 콘솔에 경고를 표시합니다.

피험자는 잘 지내나요?

JavaScript의 객체와 배열은 참조로 전달되기 때문에 특별한 경우입니다. 이는 구성 요소가 개체 소품의 중첩된 속성을 직접 수정할 수 있음을 의미합니다. 그러나 Vue는 중첩된 객체 속성의 수정에 대해 경고하지 않습니다(이러한 수정을 추적하면 성능이 저하됩니다). 따라서 이러한 예기치 않은 변경으로 인해 애플리케이션에서 감지 및 디버깅이 어려운 문제가 발생할 수 있습니다.

대부분의 경우 기본 값을 v-model으로 사용합니다. 그러나 양식 구성 요소를 작성할 때와 같은 일부 경우에는 객체를 처리할 수 있는 사용자 정의 v-model가 필요할 수 있습니다. 이는 중요한 질문으로 이어집니다.

위의 함정을 피하면서 객체를 처리하기 위해 사용자 정의 v-model를 구현하는 방법은 무엇입니까?

토론 질문

한 가지 방법은 쓰기 가능한 계산 속성이나 defineModel도우미 함수를 사용하는 것입니다. 그러나 두 솔루션 모두 중요한 단점이 있습니다. 즉, 원본 개체를 직접 수정하므로 명확한 데이터 흐름을 유지하려는 목적이 무산됩니다.

이 문제를 설명하기 위해 "양식" 구성 요소의 예를 살펴보겠습니다. 이 구성 요소는 양식의 값이 변경될 때 개체의 업데이트된 복사본을 상위 구성 요소로 다시 내보내도록 설계되었습니다. 우리는 쓰기 가능한 계산 속성을 사용하여 이를 달성하려고 노력할 것입니다.

이 예에서 쓰기 가능한 계산 속성은 여전히 ​​원본 객체를 수정합니다.

<code class="language-javascript">import { computed } from 'vue';
import { cloneDeep } from 'lodash-es';

type Props = {
  modelValue: { name: string; email: string; };
};

const props = withDefaults(defineProps<Props>(), {
  modelValue: () => ({ name: '', email: '' }),
});

const emit = defineEmits<{
  'update:modelValue': [value: Props['modelValue']];
}>();


const formData = computed({
  // 返回的getter对象仍然是可变的
  get() {
    return props.modelValue;
  },
  // 注释掉setter仍然会修改prop
  set(newValue) {
    emit('update:modelValue', cloneDeep(newValue));
  },
});</code>
로그인 후 복사
로그인 후 복사

이것은 작동하지 않습니다. getter에서 반환된 개체가 여전히 변경 가능하여 원래 개체가 예기치 않게 수정되기 때문입니다.

defineModel 마찬가지다. update:modelValue은 구성 요소에서 방출되지 않으며 개체 속성은 경고 없이 수정됩니다.

솔루션

이 상황을 처리하는 "Vue 방식"은 내부 반응 값을 사용하여 객체를 표현하고 두 개의 관찰자를 구현하는 것입니다.

  1. 관찰자는 modelValue prop의 변경 사항을 모니터링하고 내부 값을 업데이트합니다. 이렇게 하면 내부 상태에 상위 구성 요소가 전달한 최신 prop 값이 반영됩니다.
  2. 관찰자는 내부 값의 변화를 관찰합니다. 내부 값이 업데이트되면 원래 개체를 직접 수정하지 않도록 개체의 새로 복제된 버전을 상위 구성 요소로 내보냅니다.

이 두 관찰자 사이의 끝없는 피드백 루프를 방지하려면 modelValue prop에 대한 업데이트가 실수로 내부 값에 대해 관찰자를 다시 트리거하지 않도록 해야 합니다.

<code class="language-javascript">const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
<template></template></code>
로그인 후 복사
로그인 후 복사

“이건 너무하다!”라고 생각하시는지 알고 있습니다. 어떻게 하면 더 단순화할 수 있는지 살펴보겠습니다.

VueUse로 솔루션을 단순화하세요

이 로직을 재사용 가능한 합성 함수로 추출하는 것은 프로세스를 단순화하는 좋은 방법입니다. 하지만 좋은 소식은 우리는 그렇게 할 필요조차 없다는 것입니다! VueUse의 useVModel 결합 기능은 이 문제를 해결하는 데 도움이 될 수 있습니다!

VueUse는 구성된 유틸리티 중 "스위스 군용 칼"이라고도 불리는 강력한 Vue 유틸리티 라이브러리입니다. 완전히 트리쉐이킹이 가능하기 때문에 패키지 크기가 커질 걱정 없이 필요한 부분만 사용할 수 있습니다.

다음은 useVModel을 사용하여 리팩토링하기 전의 예입니다.

<code class="language-javascript">import { computed } from 'vue';
import { cloneDeep } from 'lodash-es';

type Props = {
  modelValue: { name: string; email: string; };
};

const props = withDefaults(defineProps<Props>(), {
  modelValue: () => ({ name: '', email: '' }),
});

const emit = defineEmits<{
  'update:modelValue': [value: Props['modelValue']];
}>();


const formData = computed({
  // 返回的getter对象仍然是可变的
  get() {
    return props.modelValue;
  },
  // 注释掉setter仍然会修改prop
  set(newValue) {
    emit('update:modelValue', cloneDeep(newValue));
  },
});</code>
로그인 후 복사
로그인 후 복사

훨씬 더 간단해요!

그렇습니다! 우리는 하위 구성 요소에서 직접 수정하지 않고 Vue에서 v-model을 사용하여 개체를 올바르게 사용하는 방법을 살펴보았습니다. 관찰자를 사용하거나 VueUse의 useVModel과 같은 구성 기능을 활용함으로써 애플리케이션에서 명확하고 예측 가능한 상태 관리를 유지할 수 있습니다.

다음은 이 기사의 모든 예가 포함된 Stackblitz 링크입니다. 자유롭게 탐색하고 실험해 보세요.

읽어주셔서 감사하고 즐거운 코딩 되세요!

위 내용은 Vue에서 v-model과 함께 객체를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿