# ์ปดํฌ๋„ŒํŠธ์˜ ์ฝ”๋“œ๋งˆ์ € ์žฌ์‚ฌ์šฉํ•˜๋Š” ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ

# ์ •์˜

๋ทฐ์˜ ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฆฌ์•กํŠธ์˜ ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ธฐ์›๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฆฌ์•กํŠธ์˜ ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ ์†Œ๊ฐœ ํŽ˜์ด์ง€ (opens new window)๋ฅผ ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ •ํ™•ํ•œ ์ •์˜๊ฐ€ ๋‚˜์™€ ์žˆ์Šต๋‹ˆ๋‹ค. A higher-order component (HOC) is an advanced technique in React for reusing component logic. ์ด ๋ง์„ ์ •๋ฆฌํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ๋กœ์ง(์ฝ”๋“œ)์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ณ ๊ธ‰ ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค

# ๋ฐ˜๋ณต๋˜๋Š” ์ปดํฌ๋„ŒํŠธ ๋กœ์ง

์—ฌ๊ธฐ์„œ ์ปดํฌ๋„ŒํŠธ์˜ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๋ง์ด ๋ฌด์Šจ ์˜๋ฏธ์ผ๊นŒ์š”? ์ด ํ‘œํ˜„์—์„œ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ ๋กœ์ง์ด๋ž€ ๋ทฐ์—์„œ ์ธ์Šคํ„ด์Šค ์˜ต์…˜์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋กœ ๋ฐ”๋กœ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

<!-- ProductList.vue -->
<template>
  <section>
    <ul>
      <li v-for="product in products">
        ...
      </li>
    </ul>
  </section>
</template>

<script>
import bus from './bus.js';

export default {
  name: 'ProductList',
  mounted() {
    bus.$emit('off:loading');
  },
  // ...
}
</script>
<!-- UserList.vue -->
<template>
  <div>
    <div v-for="product in products">
      ...
    </div>
  </div>
</template>

<script>
import bus from './bus.js';

export default {
  name: 'UserList',
  mounted() {
    bus.$emit('off:loading');
  },
  // ...
}
</script>

์œ„ ์ฝ”๋“œ๋Š” ProductList ๋ผ๋Š” ์ปดํฌ๋„ŒํŠธ์™€ UserList ์ปดํฌ๋„ŒํŠธ์˜ ๋กœ์ง์„ ์ •์˜ํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ๋‘ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ๊ฐ ์ƒํ’ˆ๊ณผ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์„œ๋ฒ„์—์„œ ๋ฐ›์•„์™€ ํ‘œ์‹œํ•ด์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ๋ผ๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ, ๊ณตํ†ต์ ์œผ๋กœ ๋“ค์–ด๊ฐ€๋Š” ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

name: '์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„',
mounted() {
  bus.$emit('off:loading');
},

name์€ ์ปดํฌ๋„ŒํŠธ์˜ ์ด๋ฆ„์„ ์ •์˜ํ•ด์ฃผ๋Š” ์†์„ฑ์ด๊ณ , mounted()์—์„œ ์‚ฌ์šฉํ•œ ์ด๋ฒคํŠธ ๋ฒ„์Šค๋Š” ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค ๋ฐ›์•„์™”์„ ๋•Œ ์Šคํ”ผ๋„ˆ๋‚˜ ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฐ”์™€ ๊ฐ™์€ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ์™„๋ฃŒํ•ด์ฃผ๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์ด ๋‘ ์ปดํฌ๋„ŒํŠธ ์ด์™ธ์—๋„ ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ ๋ชฉ๋ก์„ ๋ฐ›์•„์™€ ํ‘œ์‹œํ•ด์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋˜ ๋น„์Šทํ•œ ๋กœ์ง์ด ๋ฐ˜๋ณต๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ๋•Œ ์ด ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ค„์—ฌ์ค„ ์ˆ˜ ์žˆ๋Š” ํŒจํ„ด์ด ๋ฐ”๋กœ ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.

# ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฐ˜๋ณต ์ฝ”๋“œ ์ค„์ด๊ธฐ

์ด ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// CreateListComponent.js
import bus from './bus.js'
import ListComponent from './ListComponent.vue';

export default function createListComponent(componentName) {
  return {
    name: componentName,
    mounted() {
      bus.$emit('off:loading');
    },
    render(h) {
      return h(ListComponent);
    }
  }
}

์œ„ ์ฝ”๋“œ๋Š” CreateListComponent๋ผ๋Š” ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ ์šฉํ•  ์ปดํฌ๋„ŒํŠธ๋“ค์˜ ๊ณตํ†ต ์ฝ”๋“œ๋“ค(mounted, name ๋“ฑ)์„ ๋ฏธ๋ฆฌ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์ด์ œ ์ด ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ• ๊นŒ์š”? ์•„๋ž˜๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// router.js
import createListComponent from './createListComponent.js';

new VueRouter({
  routes: [
    {
      path: 'products',
      component: createListComponent('ProductList')
    },
    {
      path: 'users',
      component: createListComponent('UserList')
    },
    ...
  ]
})

์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ํ•˜์ด ์˜ค๋” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž„ํฌํŠธ ํ•˜๊ณ , ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ ์ด๋ฆ„๋งŒ ์ •์˜๋ฅผ ํ•ด์ฃผ๋ฉด ์ปดํฌ๋„ŒํŠธ์˜ ๊ธฐ๋ณธ ๊ณต์šฉ ๋กœ์ง์ธ mounted(), name๋ฅผ ๊ฐ€์ง€๊ณ  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค ๋ถˆ ํ•„์š”ํ•˜๊ฒŒ ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ •์˜ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.