Vue.js (17) 컴포넌트 props

Devcury·2022년 9월 10일
3

vue.js

목록 보기
19/27

먼저 부모의 컴포넌트에서 자식컴포넌트를 사용하는 코드를 작성해보자.

부모 컴포넌트이다. 사실 처음 vue를 생성했을때 보이는 화면이랑 비슷하다.

다음은 자식 컴포넌트이다.

props에 message라는 props에 관한 값을 정의하였다.
type은 props로 받을 변수의 타입이며, default는 props가 없을때 default 값이다. 위의 두 내용을 가장 많이 사용한다.

그외에 required, validator가 있다. required는 기본값이 false로 true 설정하면 부모에서 해당 prop을 넘겨주지 않을 때 경고 로그를 띄워준다. validator는 검증하는 함수인데, prop값이 정상적인 값인지 체크하여 true를 리턴할 경우 정상 false를 리턴하면 검증 실패로 경고 로그를 띄워주는 식이다.

위의 모습이 사용예제이다.

어찌되었든 위의 모습까지는 처음에 vue CLI로 vue 프로젝트를 생성하였을때 보이는 모습과 유사하다.

이러한 컴포넌트들의 props를 좀 더 살펴보자.

단순한 String은 위의 형태로 보여줄 수 있지만, 다른 형태들은 좀 다르다. 하나씩 살펴보도록 하자.

숫자를 표시하는데 부모쪽에서 태그 속성을 v-bind를 통하여 표현하였다. v-bind를 사용하지 않으면 모든 속성들은 다 문자열로 처리가 된다.

위의 형태는 문자열이지만 data안에 선언된 변수는 v-bind로 넘겨주어야 한다. 즉 커스텀 컴포넌트도 동적인 props v-bind, 정적인 문자열은 v-bind를 사용하지 않아도 된다는 점이다.

위의 형태는 boolean 값을 처리한 형태이다.

그외 props에 추가적인 type은 props 상세히 에서 참고 할 수 있다. 위의 사진은 해당 홈페이지의 일부 내용이다.

그렇다면 부모에서 list를 props로 보내고 해당 list를 출력하는 예제를 작성해보도록 하자.

과일 목록을 부모컴포넌트에서 작성한다.

props에서 fruits를 받아주도록 설정했는데, 여기서 주목해야할 점이 default이다. array나 object같은 reference형태의 type들은 이렇게 선언을 해주어야 한다. 그렇지 않으면 모두 같은 객체를 공유하는 형태가 되어버리기 때문에 주의해야한다.

결과 화면이다.

props의 내용은 this. 붙히면 다른곳에서도 이렇게 사용가능하다.

다음은 props를 통하여 부모의 값을 변경하는 형태를 만들어보자.

  • ParentView.vue
<template>
  <div>
    <ChildView
      :fruits="fruits"
      @change-select="change"
      :selected="selected"
    ></ChildView>
  </div>
</template>

<script>
import ChildView from "@/views/ChildView2.vue";

export default {
  data() {
    return {
      fruits: [
        { name: "사과", key: "apple" },
        { name: "복숭아", key: "peach" },
        { name: "오렌지", key: "orange" },
        { name: "딸기", key: "strawberry" },
      ],

      selected: [],
    };
  },

  components: {
    ChildView,
  },

  methods: {
    change(value) {
      this.selected = value;
    },
  },

  watch: {
    selected: {
      handler(value) {
        console.log(value);
      },
    },
  },
};
</script>

<style></style>
  • ChildView.vue
<template>
  <div>
    <ul>
      <select multiple v-model="_selected">
        <option v-for="fruit in fruits" :key="fruit.key" :value="fruit.key">
          {{ fruit.name }}
        </option>
      </select>
    </ul>
    <p>총 과일 갯수 : {{ totalLength }}</p>
  </div>
</template>

<script>
export default {
  props: {
    fruits: {
      type: Array,
      default: () => {
        return [];
      },
    },
    selected: {
      type: Array,
      default: () => {
        return [];
      },
    },
  },

  computed: {
    totalLength() {
      return this.fruits.length;
    },

    _selected: {
      set(value) {
        this.$emit("changeSelect", value);
      },
      get() {
        return this.selected;
      },
    },
  },
};
</script>

<style></style>

fruits라는 리스트를 넘기고, selected에 선택된 값들의 key가 저장 되게 되는 컴포넌트이다. 이러한 컴포넌트를 만들어두면 어떤 리스트든지 사용 가능한 컴포넌트가 될 수 있다.

그리고 선택할때마다 부모에서 선언한 watch에서 감지가 되는 것으로 부모의 selected가 변한다는것을 알 수 있다.

여기서 주목해야 할 부분을 살펴보자.

위의 형태인데 먼저 태그의 속성은 대소문자 구분이 없기 때문에 이러한 형태로 표기해준다.

그리고 함수는 v-on을 통하여 넘긴다.

여기서 자식 컴포넌트는 props로 넘어온 selected를 바로 사용하지 않았다. 여기서 주목해야할 점은 자식 컴포넌트 내에서 부모의 props를 변경하지 않아야 한다는 점이다. 자식의 props는 read-only라고 생각하는 점이 맞을 것이다. 계속 살펴보자면, 자식에서 computed를 통하여 props의 selected를 사용해주었고 v-model에 넣음으로 set할때마다 부모에서 넘겨준 change-select에 해당 하는 함수를 호출한다. this.$emit('change-select', value) 에 해당하는 내용이다. 부모에서 넘어온 함수를 이렇게 호출 하고 뒤에 추가적인 파라미터를 넘기면 부모의 함수에서 받을 수 있게 된다. 이렇게 구성하게 되면 자식에서 부모의 props를 직접 변경하지 않게 된다. 역시 부모쪽에서 변경되면 자식의 값도 같이 변경되게 때문에 문제 없는 형태가 만들어진다.

해당 예제는 단순하게 구성한 것으로 여기서 중요한 포인트는 부모에게서 넘겨받은 props는 read-only 형태로 사용해야하며, 부모의 값을 변경해줄때는 함수를 호출하여 바꿔주면 된다는 점이다.

profile
잘하고 싶은 개발자

0개의 댓글