container & presentational 컴포넌트

부모에서 데이터 변경을 처리하고 자식은 해당 데이터를 표현만 하는 방식을 이야기한다.

부모 컴포넌트인 index에서 일단은 props로 검색한 키워드 데이터를 자식 컴포넌트인 SearchInput으로 내려보낸다.

<template lang="">
  <div class="app">
    <main>
      **<SearchInput :search-keyword="searchKeyword"></SearchInput>**
      ...
    </main>
  </div>
</template>
<script>
import axios from 'axios'
import SearchInput from '@/components/SearchInput.vue'

export default {
  name: 'IndexPage',
  components: { SearchInput },
  data() {
    return {
      **searchKeyword: 'hi',**
    }
  },
  ...
</script>
<style scoped>
</style>

그럼 자식 컴포넌트는 해당 데이터를 받아 표현하는 역할만 수행하기 때문에 props로 받은 searchKeyword를 input 요소의 value와 바인드해서 나타내준다.

<template>
  <div>
    <input type="text" **:value="searchKeyword"** />
    <!--prop으로 내려받은 searchKeyword가 바인드되어 input 창에 나타난다-->
    <button>search</button>
  </div>
</template>

<script>
export default {
  name: 'SearchInput',
  props: {
    **searchKeyword**: {
      type: String,
      default: () => '',
    },
  },
}
</script>

<style scoped></style>

input에 입력된 값 부모 컴포넌트로 올리기

input요소의 input이라는 이벤트(내가 임의로 만든 이름)가 발생할 때마다 $emit을 사용하여 $event.target.value의 값을 위로 올릴 것이다.

<template>
  <div>
    <input
      type="text"
      :value="searchKeyword"
      **@input="$emit('input', $event.target.value)"**
    />
    <button>search</button>
  </div>
</template>

<script>
export default {
  name: 'SearchInput',
  props: {
    searchKeyword: {
      type: String,
      default: () => '',
    },
  },
}
</script>

<style scoped></style>

밑에서 위로 올라간 input 이벤트의 데이터들을 부모 컴포넌트에서 받아서 사용하기로 한다. updateSearchKeyword 메서드를 사용해서 searchKeyword 데이터를 바꾼다.

<template lang="">
  <div class="app">
    <main>
      <SearchInput
        :search-keyword="searchKeyword"
        **@input="updateSearchKeyword"**
      ></SearchInput>
      ...
    </main>
  </div>
</template>
<script>
import axios from 'axios'
import SearchInput from '@/components/SearchInput.vue'

export default {
  name: 'IndexPage',
  components: { SearchInput },
  data() {
    return {
      **searchKeyword**: 'hi',
    }
  },
	 ...
  methods: {
    ...
    **updateSearchKeyword**(**keyword**) {
      this.searchKeyword = **keyword**
    },
  },
}
</script>
<style scoped>
</style>

사실 이렇게 v-bind와 v-on 둘을 잘 조합한 게 v-model과 같은 역할을 하기는 한다.

v-model로 바꿔보자.

부모 컴포넌트

<template lang="">
  <div class="app">
    <main>
      <!-- <SearchInput
        :search-keyword="searchKeyword"
        @input="updateSearchKeyword"
      ></SearchInput> -->
      **<SearchInput v-model="searchKeyword"></SearchInput>**
      ...
    </main>
  </div>
</template>

자식 컴포넌트

자식 컴포넌트에서 v-model에 바인드 된 prop을 받고 싶다면 value란 값을 사용하면 된다. 일반적으로 prop은 부모에서 정해준 이름을 가지고 와서 사용하지만, v-model은 그렇지 않다.

<template>
  <div>
    <input
      type="text"
      **:value="value"**
      @input="$emit('input', $event.target.value)"
    />
    <button>search</button>
  </div>
</template>

<script>
export default {
  name: 'SearchInput',
  props: {
    **value**: {
      type: String,
      default: () => '',
    },
  },
}
</script>

<style scoped></style>