본문 바로가기

Study/JavaScript

[Vue.js] props

props는 properties의 준말으로, Vue에서 부모 컴포넌트가 가지고 있는 변수를 자식 컴포넌트에게 "상속"(물론 OOP에서의 상속과는 결이 다르다)해주기 위해 사용되는 기능이다.

 

다음과 같은 부모-자식 컴포넌트를 생각해보자.

 

<!-- Parent.vue -->
<script setup>
import { ref } from 'vue';
import Child from '@/components/Child.vue';

const name = ref('홍길동');
const age = ref(20);

function changeName() {
 name.value = "Gildong Hong";
};
</script>

<template>
  <h1>PARENT</h1>
  <div>{{ name }}</div>
  <div>{{ age }}</div>
  <Child
    :nameProp="name"
    :ageProp="age"
    @change-name="changeName"
  />
</template>

<style scoped>
</style>


<!-- Child.vue -->
<script setup>
const props = defineProps({
  nameProp: String,
  ageProp: Number,
});

const emit = defineEmits(['changeName']);

function changeName() {
  emit('changeName');
}
</script>

<template>
  <h2>child</h2>
  <div>{{ nameProp }}</div>
  <div>{{ ageProp }}</div>
  <button @click="changeName">개명 request</button><br>
  <button @click="ageProp = 21">take 떡국</button>
</template>

<style scoped>
</style>

 

 

Vue.js에서는 props라는 기능을 통해 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달한다. props의 개략적인 흐름은 다음과 같다.

 

1) 전달될 데이터인 name과 age는 ref()를 통해 반응형 변수로 설계

2) 자식 컴포넌트를 HTML 내에서 호출할 때 어떤 데이터를 props로 전달해줄지 명시

3) 자식 컴포넌트에서 defineProps를 통해 전달 받은 데이터의 이름과 자료형을 명시

4) 와! 이제 전달 받은 props를 사용할 수 있다!

 

자세히 살펴보면 props 외에 emit이라는 이름도 보인다. emit은 방출하다라는 의미를 가지고 있다. 자식 컴포넌트에서 부모 컴포넌트 방향으로 어떠한 신호를 방출하는 거라고 해석할 수 있다. emit의 개략적인 흐름은 다음과 같다.

 

1) 자식 컴포넌트에서 발생 가능한 이벤트의 종류를 defineEmits를 통해 선언

2) 특정 v-on과 특정 이벤트를 매칭. 예제의 경우에는 버튼을 클릭시 changeName 함수가 실행되며, changeName 함수는 'changeName' 이벤트와 짝지어져 있다.

3) emit된 이벤트를 수신하기 위해, 부모 컴포넌트에서 자식 컴포넌트를 호출하는 지점에서 v-on으로 emit된 이벤트를 명시한다. 그리고 해당 이벤트를 수신했을 때의 액션을 지정한다.

4) 와! 이제 전달 받은 이벤트에 따라 액션이 실행된다!

 

주어진 예제에서 자식 컴포넌트에 속한 버튼을 누르자 부모와 자식 컴포넌트의 이름이 모두 'Gildong Hong'으로 바뀌는 것을 확인할 수 있다.

 

그러면 두 번째 버튼인 'take 떡국'을 누르면 무슨 일이 일어날까? 아쉽지만 아무 일도 일어나지 않는다. 정확히는 다음과 같은 에러가 콘솔창에 출력된다.

 

 

[Vue warn] Set operation on key "ageProp" failed: target is readonly. Proxy(Object) {nameProp: '홍길동', ageProp: 20}

 

 

readonly라는 표현을 볼 수 있다. ref()로 감싼 변수를 내려보냈다고 해도, 단방향 데이터 흐름을 유지하기 위해 자체적으로 props를 readonly로 전환하는 과정이 defineProps에 포함되어 있는 것. 만약 자식 컴포넌트에서의 props만 바꾸고 싶다면 다른 변수에 할당해야 한다.(자료들을 보면 예전 버전에서는 그냥 됐던 것 같기도 하다.)

 

다음은 생각해볼 만한 예제다. 버튼을 눌렀을 때의 결과를 예상해보는 건 재밌는 게임이 될 것이다.

 

<!-- Parent.vue -->
<template>
  <div>
    <p>First element of the first array in parent: {{ nestedArray[0][0] }}</p>
    <p>last element of the array in parent: {{ nestedArray[2] }}</p>
    <p>num in parent: {{ num }}</p>
    <hr>
    <child
      :nestedArray="nestedArray"
      :num="num"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue';
import Child from './Child.vue';

const nestedArray = ref([[1, 2], [3, 4], 3]);
const num = ref(1)
</script>


<!-- Child.vue -->
<template>
  <div>
    <p>First element of the first array in child: {{ nestedArray[0][0] }}</p>
    <p>last element of the array in child: {{ nestedArray[2] }}</p>
    <p>num in child: {{ num }}</p>
    <button @click="changeValue">Change Value in Child</button>
  </div>
</template>

<script setup>
import { defineProps } from 'vue';

const props = defineProps({
  nestedArray: Array,
  num: Number,
});

function changeValue() {
  props.nestedArray[0][0] = 99;
  props.nestedArray[2] = 98;
  props.num = 97
}
</script>

'Study > JavaScript' 카테고리의 다른 글

클래스와 프로토타입  (0) 2024.06.12
this  (0) 2024.04.21