visitors
98
일일 방문자 수

05월 31일 (토) 오전 06:41

Responsive image

아래쪽으로 데이터 전달 prop

Created: 2023. 05. 10 09:53 오후
Updated: 2023. 05. 26 08:22 오전

컴포넌트를 분리하여 UI에 맞게 필요한 코드만 볼 수 있어서 좋아졌습니다. 그러나 코드가 분리되면서, 공용으로 사용하던 변수가 컴포넌트들이 따로 사용하게 되면서 일치하지 않는 문제가 발생했습니다.

이 값을 주고받을 수 있도록 컴포넌트 간의 통신이 필요합니다. 그러나 모든 컴포넌트가 서로 통신하게 되면 복잡해질 가능성이 있습니다.

따라서, 컴포넌트는 부모-자식 관계에 있는 컴포넌트끼리만 통신이 가능하도록 설계되었습니다. 이렇게 함으로써, 컴포넌트 간의 통신이 일어날 때 어디서부터 어디까지의 범위에서 일어나는지 명확하게 파악할 수 있으며, 컴포넌트 간의 의존성이 낮아져 코드를 재사용하거나 유지보수하기 쉬워집니다. 또한, 부모-자식 관계로 컴포넌트 간의 통신을 제한함으로써 코드의 복잡도를 낮출 수 있고, 앱의 성능을 향상시킬 수 있습니다.

그래서 MenuBar 컴포넌트와 PostList 컴포넌트가 같은 값을 들고 있으려면 부모 컴포넌트인 App 컴포넌트가 selectedCategory 값을 관리해줘야합니다.

부모 컴포넌트는 이 값을 자식 컴포넌트에 전해주기만 하면 됩니다. 이 때 사용하는 것이 prop입니다.

prop

prop은 property의 줄임말로, 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달하기 위해 사용됩니다. 자식 컴포넌트를 사용할 때 속성처럼 값을 넣어서 전달합니다.

html
App.js
      <MenuBar my-property="hello">
    

실제로 HTML에는 저런 속성이 없습니다. 그래서 이렇게 실제로는 해당 컴포넌트의 제일 상단 태그에 속성이 그대로 들어갑니다.

이 속성을 컴포넌트 데이터로써 전달하려면 자식 컴포넌트도 받을 준비를 해야합니다. props 속성에 받고자 하는 속성의 이름을 배열로 전달해주면 됩니다. 그리고 setup 함수의 첫 번째 전달인자를 통해 해당 값을 가져오게 됩니다.

실제로 HTML에는 이러한 속성이 없습니다. 따라서 해당 컴포넌트의 상단 태그가 하나만 있다면 자동으로 그 태그에 들어가게 됩니다.

이 속성을 컴포넌트 데이터로 전달하려면 자식 컴포넌트도 준비해야 합니다. props 속성에 받고자 하는 속성의 이름을 배열로 전달하고, setup 함수의 첫 번째 인자를 통해 해당 값을 가져올 수 있습니다.

javascript
MenuBar.js
      export default {
  props: ["myProperty"],
  setup(props) {
    console.log(props);
    console.log(props.myProperty);
	}
}
    

Proxy 객체를 전달 받았고 그 안에 myProperty 값이 들어있습니다.

만약 부모가 아무 속성도 넣지 않았다면 null 값이 나타납니다.

props에 등록된 값은 setup 함수 뿐만 아니라 template에서도 사용할 수 있습니다.

javascript
      export default {
  props: ["myProperty"],
  template: `
    <div>{{ myProperty }}</div>
  `,
}
    
      Q] 왜 HTML에서는 my-property 이고 Javascript에서는 myProperty인가요? 

A] 두 언어의 변수명 규칙이 다르기 때문입니다. HTML에서는 속성 값을 myProperty라고 넣어도 대소문자를 구분하지 않아서 myproperty라고 인식합니다. 그래서 하이픈(-)으로 단어 구분 하는 kebab-case 기법을 사용합니다. 반면 Javascript는 변수명에 하이픈을 사용할 수 없기 때문에 중간 단어가 대문자인 camelCase 기법으로 변수명을 짓습니다.

Vue는 이러한 변수명 기법 차이의 불편함을 해소하기 위해, 속성에 넣은 kebab-case를 자동으로 인식하고 camelCase로 변환해줍니다.
    

props 값 제한

props는 자식이 음식 투정하는 것처럼, 특정한 타입의 값만 받도록 할 수 있습니다. 이를 위해 객체를 배열 대신 전달하고 추가적인 정보를 제공해야 합니다.

javascript
      export default {
  props: {
    // 숫자만 받는다!
    propA: Number,

    // 문자열 또는 숫자만 받는다!
    propB: [String, Number],

    // 문자열로 받는데 이 값은 꼭 넣어줘라!
    propC: {
      type: String,
      required: true,
    },

    // 숫자를 받는데 아무값도 안주면 100으로 들고 있겠다!
    propD: {
      type: Number,
      default: 100,
    },
  },
};
    

만일 null을 넣을 경우엔 배열처럼 어떤 제한도 없이 다 받을 수 있습니다. 객체든 함수든 말이죠..

loading

v-bind를 써야할 순간

우린 단순히 hello를 전달하려고 하는게 아닙니다. selectedCategory 가 가진 값을 postList에 전달해서 글 목록 타이틀로 보여줘야합니다. 그러니 다음과 같이 바꿔보겠습니다.

App.js에서 selectedCategory 만들어주고 이를 속성으로 전달하겠습니다. 속성명도 동일하게 하겠습니다.

javascript
      import { ref } from "https://unpkg.com/vue@3/dist/vue.esm-browser.js";
import MenuBar from "./components/MenuBar.js";
import PostList from "./components/PostList.js";

export default {
  template: `
    <MenuBar />
    <PostList :selected-category="selectedCategory" />
	`,
  setup() {
    const selectedCategory = ref("HTML");
    return {
      selectedCategory,
    };
  },
  components: {
    MenuBar,
    PostList,
  },
};
    

그리고 postList에서 props 속성에 selectedCategory를 추가합니다.

javascript
PostList.js
      export default {
  template: `
    ...
    <li v-for="item in postList[selectedCategory]" :key="item.id">
    ...
  `,
  props: ["selectedCategory"],
  setup() {
    const postList = {
      HTML: [
        { id: 0, title: "HTML 기본 1" },
        { id: 1, title: "HTML 기본 2" },
      ],
      CSS: [{ id: 2, title: "CSS 기본 1" }],
    };

    return {
      postList,
      props,
    };
  },
};
    

어쨋든 글 목록이 상위 App 값에 잘 전달된 것 같습니다!! 그런데 클릭해도 아무런 변화가 없네요.

loading

뭐야 그럼 이전이랑 다를게 없잖아요!

loading

네 그렇지만 한 가지 보여드릴게 있습니다. 크롬 확장프로그램으로 깔았던 Vue devtools를 사용해볼 때입니다. 제일 우측에 있는 (없다면 >>화살표를 클릭해서) Vue를 클릭해주세요.

그러면 아래에 최상단 컴포넌트에서 setup에서 만든 변수들이 나열되어 있습니다. selectedCategory: "HTML" (Ref) 라는 항목을 볼 수 있습니다.

HTML을 더블클릭해서 “CSS"“Javascript" 로 바꿔보세요!

loading

최상위 컴포넌트의 selectedCategory 값이 변경되면, PostList에 전달된 값도 반응형이기 때문에 변경 사항이 반영됩니다.

그렇다는 것은 메뉴바의 클릭이 문제입니다. 왜냐하면 메뉴 바에서 클릭했을 때 바꾸어야할 selectedCategory 값은 부모 컴포넌트가 가지고 있기 때문입니다.

이렇게 자식 컴포넌트에서 이벤트가 발생하지만 처리는 부모 컴포넌트에서 수행해야 하는 상황이 발생할 수 있습니다. 이 경우, 이벤트를 전달하여 상위 컴포넌트가 처리할 수 있도록 해야합니다. 자식 컴포넌트가 부모 컴포넌트에 데이터를 전달한 것처럼, 자식 컴포넌트에서 부모 컴포넌트로 이벤트를 전달하는 방법이 있습니다. 다음 글에서 자세히 설명하겠습니다.