ahn heejong

React๋ฅผ Vue.js๋ณด๋‹ค ์„ ํ˜ธํ•˜๋Š” ์ด์œ 

2018-03-03
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ
React
Vue.js
ํ”„๋ก ํŠธ์—”๋“œ

๋“ค์–ด๊ฐ€๋ฉฐ

ํšŒ์‚ฌ์—์„œ ๋‚˜๋Š” ์ฃผ๋กœ SPA ๊ธฐ๋ฐ˜์˜ ์›น ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ๊ฐœ๋ฐœํ•œ๋‹ค. ์ „ ํšŒ์‚ฌ์—์„œ๋Š” React๋ฅผ, ํ˜„ ํšŒ์‚ฌ์—์„œ๋Š” Vue.js๋ฅผ ๋ฉ”์ธ ๊ธฐ์ˆ ๋กœ ์‚ฌ์šฉํ–ˆ์œผ๋‹ˆ ์ด ๋ถ„์•ผ์—์„œ ์š”์ƒˆ ๊ฐ€์žฅ ๋งŽ์€ ๊ด€์‹ฌ์„ ๋ฐ›๋Š” ๋‘ ๊ธฐ์ˆ ์„ ๊ฐ๊ฐ ๋ช‡ ๋‹ฌ ์”ฉ ๊ฒฝํ—˜ํ•œ ์…ˆ์ด๋‹ค. ๊ทธ ๊ฒฐ๊ณผ ๋‚˜๋ฆ„๋Œ€๋กœ ๋‚ด๋ฆฐ ๊ฒฐ๋ก ์ด ์žˆ๋Š”๋ฐ, ์„ ํƒ๊ถŒ์ด ์žˆ๋Š” ์ƒํ™ฉ์—์„  ๋ฌด์กฐ๊ฑด React๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ตœ๊ทผ ์›น ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ์˜ ๊ธฐ์ˆ  ์„ ํƒ์— ๋Œ€ํ•ด ์งยท๊ฐ„์ ‘์ ์œผ๋กœ ์กฐ์–ธ์„ ์š”์ฒญ๋ฐ›์•˜๋Š”๋ฐ, ๋งค๋ฒˆ ์œ„์˜ ์ž…์žฅ์„ ๊ธฐ์ดˆ๋กœ ๋Œ€๋‹ตํ–ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋น„์Šทํ•œ ๋Œ€๋‹ต์„ ์„ธ๋„ค๋ฒˆ ์ฏค ํ•˜๊ณ  ์žˆ์ž๋‹ˆ ์ด๋Ÿฐ ์ž…์žฅ์„ ๊ฐ–๊ฒŒ ๋œ ์ด์œ ๋ฅผ ํ•œ ๋ฒˆ ๊ธ€๋กœ ์ •๋ฆฌํ•ด๋‘๋ฉด ํŽธํ•˜๊ธฐ๋„ ํ•˜๊ณ , ์ข€ ๋” ๋„์›€์ด ๋  ์ˆ˜ ์žˆ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด์„œ ์ด ๊ธ€์„ ์ ๊ฒŒ ๋˜์—ˆ๋‹ค.

๊ธ€์— ๋“ค์–ด๊ฐ€๊ธฐ ์•ž์„œ ์ด ๊ธ€์˜ ์ œ๋ชฉ์ด โ€React๊ฐ€ Vue.js๋ณด๋‹ค ์šฐ์›”ํ•˜๊ณ  ๋ชจ๋‘๊ฐ€ React๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ โ€๊ฐ€ ์•„๋‹ˆ๋ž€ ์ ์„ ๊ฐ•์กฐํ•˜๊ณ  ์‹ถ๋‹ค. ๋ชจ๋“  Vue.js ์‚ฌ์šฉ์ž๊ฐ€ React๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋งŒ๋“œ๋Š” ๊ฑด ์ด ๊ธ€์˜ ๋ชฉํ‘œ๊ฐ€ ์•„๋‹ˆ๋‹ค. ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์ง€์ , ๋˜ ๋ฏธ์ฒ˜ ์ƒ๊ฐํ•˜์ง€ ๋ชปํ•œ ์ ์— ๋Œ€ํ•œ ์˜๊ฒฌ์€ ํ™˜์˜ํ•œ๋‹ค.

๋‚ด๊ฐ€ React๋ฅผ Vue.js๋ณด๋‹ค ์„ ํ˜ธํ•˜๋Š” ์ด์œ ๋Š” ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€ ์ •๋„๋กœ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ง€์›
  • ๋‹จ์ˆœํ•œ ์ปดํฌ๋„ŒํŠธ ์ •์˜์˜ ์šฉ์˜ํ•จ
  • ๋” ๋น ๋ฅด๊ณ  ๋‹ด๋Œ€ํ•œ ๊ฐœ์„ 

ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณด์ž.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ง€์›

์ด ํ•ญ๋ชฉ์€ ์ƒ๋Œ€์ ์œผ๋กœ ๋‹ค๋ฅธ ํ•ญ๋ชฉ์— ๋น„ํ•ด React์˜ ๋น„๊ต์šฐ์œ„๊ฐ€ ๋ช…๋ฐฑํ•˜๋‹ค. React์™€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ(์ดํ•˜ TS)์˜ ๊ฒฐํ•ฉ์€ ์•„์ฃผ ๋งค๋„๋Ÿฝ๋‹ค. ํฐ ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์—†์ด๋„ SFC์™€ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ์ปดํฌ๋„ŒํŠธ ๋‘˜ ๋ชจ๋‘์˜ ํƒ€์ž…์„ ์ •ํ™•ํ•˜๊ฒŒ ๊ธฐ์ˆ ํ•  ์ˆ˜ ์žˆ๊ณ , redux๋ฅผ ๋น„๋กฏํ•œ ์ปดํŒจ๋‹ˆ์–ธ ํˆด๋„ ๋Œ€๋ถ€๋ถ„ ํ›Œ๋ฅญํ•œ ํƒ€์ž… ์ง€์›์„ ์ œ๊ณตํ•œ๋‹ค.

๋ฐ˜๋ฉด Vue.js๋Š” 2.5 ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ ๋‹น์‹œ TS ์ง€์›์˜ ํฐ ๊ฐœ์„ ์„ ํ™๋ณดํ–ˆ์ง€๋งŒ ์•„์ง๊นŒ์ง€๋„ ๋งŽ์ด ๋ฏธํกํ•˜๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด computed๋‚˜ methods ๋‚ด์˜ this ํƒ€์ž…์€ ์—ฌ์ „ํžˆ ์ œ๋Œ€๋กœ ์ถ”๋ก ๋˜์ง€ ์•Š๋Š”๋‹ค. vue-class-component๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ƒํ™ฉ์ด ์ข€ ๋‚˜์•„์ง€์ง€๋งŒ ์ด๋Š” ์•„์ง ์‹คํ—˜ ๊ธฐ๋Šฅ์ธ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜์กดํ•˜๋ฉฐ, ์ฃผ๋ฅ˜ ๋ฌธ๋ฒ•๊ณผ ์ด์งˆ์ ์ด๋‹ค. vuex์˜ ํƒ€์ž… ์ง€์› ๋˜ํ•œ redux์˜ ๊ทธ๊ฒƒ๊ณผ ๋น„์Šทํ•œ ์ˆ˜์ค€์ด ๋˜๊ธฐ๋Š” ์š”์›ํ•ด๋ณด์ธ๋‹ค.

TS์˜ ํ•„์š”์„ฑ์— ๊ณต๊ฐํ•˜์ง€ ๋ชปํ•˜๊ฑฐ๋‚˜ ๋„์ž…์ด ๋„ˆ๋ฌด ์–ด๋ ต๊ณ  ๊ท€์ฐฎ๊ฒŒ ๋Š๊ปด์ ธ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์‚ฌ๋žŒ๋“ค์„ ๊ฝค ๋ณด์•˜๋Š”๋ฐ, ๊ทธ๋Ÿฐ ์ด๋“ค์—๊ฒ ์ด ํ•ญ๋ชฉ์€ ๋ณ„๋กœ ํ•ด๋‹น ์‚ฌํ•ญ์ด ์—†๋‹ค. ๊ฐœ์ธ์ ์œผ๋ก  TS ๋„์ž…์„ ๊ถŒํ•˜๋Š” ๋ฐœํ‘œ๊นŒ์ง€ ํ•  ์ •๋„๋กœ ๊ธฐ์ˆ ์˜ ํŒฌ์ด๊ณ , ๊ทธ ์ง€์› ์ˆ˜์ค€์— ๋”ฐ๋ผ ์ƒ์‚ฐ์„ฑ์ด ๊ทน๋ช…ํ•˜๊ฒŒ ๋‹ฌ๋ผ์งˆ ์ •๋„๋กœ ์˜์กด์„ฑ์ด ํฌ๋‹ค. ๋”ฐ๋ผ์„œ Vue.js์˜ TS ์ง€์›์ด ๋ˆˆ์— ๋„๊ฒŒ ๊ฐœ์„ ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์ด ์  ํ•˜๋‚˜๋งŒ ํ•ด๋„ ๋‚˜์—๊ฒ React๋ฅผ ์„ ํƒํ•  ์ถฉ๋ถ„ํ•œ ์ด์œ ๊ฐ€ ๋  ๋“ฏ ํ•˜๋‹ค.

๋‹จ์ˆœํ•œ ์ปดํฌ๋„ŒํŠธ ์ •์˜์˜ ์šฉ์ดํ•จ

Vue.js๋Š” ์ปดํฌ๋„ŒํŠธ์— ๊ด€ํ•œ ํ…œํ”Œ๋ฆฟ, ์Šคํƒ€์ผ๊ณผ ์Šคํฌ๋ฆฝํŠธ๋ฅผ .vue ํ™•์žฅ์ž๋ฅผ ๊ฐ–๋Š” ํ•œ ํŒŒ์ผ ๋‚ด์— ๋ชจ๋‘ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋‹จ์ผ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ(Single File Component)๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์ด๋ฅผ ์‚ฌ์šฉํ•ด ํ—ˆ๊ตฌ์˜ UserList ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž.

<template>
  <ul :id="$style.userList">
    <li
      v-for="user in users"
      :key="user.id"
      :class="{
        [$style.userItem]: true,
        [$style.selected]: user.id === selectedUserId
      }">
      {{ user.name }}
    </li>
  </ul>
</template>

<script>
export default {
  data() {
    return { selectedUserId: undefined }
  },
  props: ['users']
}
</script>

<style module>
/* style definition */
</style>

React๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋Œ€๋žต ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•  ๊ฒƒ์ด๋‹ค.

import React, { Component } from 'react'
import classNames from 'classnames'
import * as styles from './UserList.css'

const UserItem = ({ user, selected }) => (
  <li className={classNames(style.userItem, { [style.selected]: selected })}>
    { user.name }
  </li>
)

export default class UserList extends Component {
  constructor(props) {
    super(props)
    this.state = { selectedUserId: undefined }
  }

  render() {
    const { users } = this.props
    const { selectedUserId } = this.state

    return (
      <ul className={styles.userList}>
        {users.map(user => (
          <li className={classNames(styles.userItem, { [styles.selected]: user.id === selectedUserId })}>
            { user.name }
          </li>
        )}
      </ul>
    )
  }
}

์ด ์‹œ์ ์—์„œ๋Š” ๋น„๊ตํ•ด๋ณด๋ฉด, Vue.js์— ๋น„ํ•ด React์˜ ๋ฌธ๋ฒ•์ด ๊ฐ–๋Š” ๋ช‡ ๊ฐ€์ง€ ๋‹จ์ ์ด ๋ˆˆ์— ๋ˆ๋‹ค.

  • styled-components๋“ฑ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ด์ƒ ์ปดํฌ๋„ŒํŠธ์˜ ์Šคํƒ€์ผ์‹œํŠธ๋ฅผ ๋ณ„๋„์˜ ํŒŒ์ผ์— ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.
  • ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ์—˜๋ฆฌ๋จผํŠธ์˜ ํด๋ž˜์Šค ๋ช…์„ ๋‹ค๋ฅด๊ฒŒ ์ฃผ๊ณ  ์‹ถ์„ ๋•Œ classnames๋“ฑ์˜ ์จ๋“œํŒŒํ‹ฐ์— ์˜์กดํ•ด์•ผ ํ•œ๋‹ค.
  • ์ƒํƒœ๋ฅผ ๊ฐ–๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•  ๋•Œ ํ•„์š”ํ•œ ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ๊ฐ€ Vue.js์— ๋น„ํ•ด ํฌ๋‹ค.

ํ•˜์ง€๋งŒ ์ด ํŒŒ์ผ ๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉ ๋  UserItem ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณ„๋„์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ๋นผ๋Š” ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž.

Vue.js์—์„œ๋Š” ๋‘ ๊ฐ€์ง€ ์„ ํƒ์ง€๊ฐ€ ์žˆ๋‹ค. ํ•˜๋‚˜๋Š” ๋ณ„๋„์˜ UserItem.vue๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด๋‹ค.

<template>
  <ul :id="$style.userList">
    <user-item
      v-for="user in users"
      :key="user.id"
      :user="user"
      :selected="user.id === selectedUserId"
    />
  </ul>
</template>

<script>
import UserItem from './UserItem.vue'

export default {
  components() {
    UserItem
  },
  data() {
    return { selectedUserId: undefined }
  },
  props: ['users']
}
</script>

<style module>
/* style definition */
</style>

๋˜๋Š” ํŒŒ์ผ ๋‚ด์—์„œ ComponentOption ๊ฐ์ฒด๋ฅผ ์ •์˜ ํ•  ์ˆ˜ ์žˆ๋‹ค.

<template>
  <ul :id="$style.userList">
    <user-item
      v-for="user in users"
      :key="user.id"
      :user="user"
      :selected="user.id === selectedUserId"
    />
  </ul>
</template>

<script>
const UserItem = {
  template: '<li :class="{ [styles.userItem]: true, [styles.selected]: selected }">{{ user.name }}</li>',
  props: ['user', 'selected']
}

export default {
  components() {
    UserItem
  },
  data() {
    return { selectedUserId: undefined }
  },
  props: {
    users: {
      type: Array,
      default: []
    }
  }
}
</script>

<style module>
/* style definition */
</style>

์ด๋Ÿฌํ•œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ ๊ฐ๊ฐ์˜ ๋‹จ์ ์„ ๊ฐ–๊ณ  ์žˆ๋‹ค.

๋จผ์ € ๋‹จ์ผ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•œ ์ ‘๊ทผ์˜ ๊ฒฝ์šฐ, ํ•œ ๊ตฐ๋ฐ์—์„œ๋งŒ ์‚ฌ์šฉ๋  ์ž‘์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•  ๋•Œ์—๋„ ๋ฌด์กฐ๊ฑด ์ƒˆ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. ์ด๋Š” ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ์˜ ์ฆ๊ฐ€๋กœ ์ด์–ด์ง„๋‹ค.

ํ•œ ํŽธ, ComponentOptions๋ฅผ ์‚ฌ์šฉํ•œ ์ ‘๊ทผ์˜ ๊ฒฝ์šฐ, ํ…œํ”Œ๋ฆฟ์„ ํ”Œ๋ ˆ์ธ ๋ฌธ์ž์—ด๋กœ ํ‘œํ˜„ํ•˜๋Š” ํƒ“์— ๋งŽ์€ ์ •๋ณด๋ฅผ ์žƒ๊ฒŒ ๋œ๋‹ค. template ๋Œ€์‹  render ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๊ทธ ์•ˆ์—์„œ JSX๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, Vue.js๊ฐ€ ๊ถŒ์žฅํ•˜๋Š” ๋ฐฉ์‹์€ ์•„๋‹ˆ๋ผ๋Š” ์ธ์ƒ์„ ๋ฐ›์•˜๋‹ค.

React์˜ ๋ฌด์ƒํƒœ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ(Stateless Functional Component)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ™์€ ์ž‘์—…์„ ์•„๋ž˜์™€ ๊ฐ™์ด ์šฐ์•„ํ•˜๊ฒŒ ํ•ด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

import React, { Component } from 'react'
import classNames from 'classnames'
import * as styles from './UserList.css'

const UserItem = ({ user, selected }) => (
  <li className={classNames(style.userItem, { [style.selected]: selected })}>
    { user.name }
  </li>
)

export default class UserList extends Component {
  render() {
    const { users } = this.props
    const { selectedUserId } = this.state

    return (
      <ul className={styles.userList}>
        {users.map(user => (
          <UserItem user={user} selected={this.selectedUserId === user.id} />
        )}
      </ul>
    )
  }
}

๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ๊ฐ€ ํ›จ์”ฌ ์ ์„ ๋ฟ๋”๋Ÿฌ, UserItem ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ถ€๋ชจ๊ฐ€ ๋˜์ ธ์ค€ ๋ฐ์ดํ„ฐ์— ์˜์กดํ•˜๋Š” ํ•จ์ˆ˜๋ผ๋Š” ์ ์ด ์ฝ”๋“œ ์ž์ฒด์—์„œ ์•„์ฃผ ๋ช…๋ฐฑํ•˜๊ฒŒ ๋“œ๋Ÿฌ๋‚œ๋‹ค.

์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž˜๊ฒŒ ์ชผ๊ฐค ๋•Œ React๋Š” Vue.js์— ๋น„ํ•ด ๋‹ค์Œ ๊ฐ•์ ์„ ๊ฐ–๋Š”๋‹ค.

  • ์ž‘์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•˜๋Š” ๋ฌธ๋ฒ•์ด ์ง๊ด€์ ์ด๊ณ  ๊ฐ„๊ฒฐํ•˜๋‹ค.
  • ์ปดํฌ๋„ŒํŠธ ์ •์˜ํ•˜๋Š” ๋‘ ๋ฌธ๋ฒ•(SFC, ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ์ปดํฌ๋„ŒํŠธ)์ด ์ƒ๋Œ€์ ์œผ๋กœ ๋” ์ผ๊ด€์ ์ด๋‹ค.
  • ํ…œํ”Œ๋ฆฟ์„ ๋ฌธ์ž์—ด๋กœ ํ‘œํ˜„ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์—ฌ๋Ÿฌ ์ •๋ณด๋ฅผ ์žƒ์–ด๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.

์ปค๋‹ค๋ž€ ๋กœ์ง์„ ํ•จ์ˆ˜๋กœ ์ชผ๊ฐœ ์˜๋„๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ธ์ฝ”๋”ฉํ•˜๊ณ  ํ”„๋กœ๊ทธ๋žจ์„ ๋ณด๋‹ค ์‰ฝ๊ฒŒ ์†Œํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ์˜๋ฏธ ๋ฉ์–ด๋ฆฌ๋กœ ๋‚˜๋ˆ„๋“ฏ, ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ชผ๊ฐœ๋Š” ์ž‘์—…๋„ ๋น„์Šทํ•œ ํšจ๊ณผ๋ฅผ ๊ฐ–๋Š”๋‹ค. React๋Š” Vue.js์— ๋น„ํ•ด UI๋ฅผ ์กฐ๊ทธ๋งˆํ•œ ์ปดํฌ๋„ŒํŠธ๋“ค์˜ ์กฐํ•ฉ์œผ๋กœ ํ‘œํ˜„ ํ•˜๋Š”๋ฐ์— ๋” ์ ํ•ฉํ•œ ๋ฌธ๋ฒ•์„ ๊ฐ–๊ณ  ์žˆ๋‹ค. ๋‚˜๋Š” ์ด๋Ÿฐ ์žฅ์ ์ด React์˜ ๋‹จ์ ์„ ์ƒ์‡„ํ•˜๊ณ  ๋‚จ์„ ์ •๋„๋ผ ์ƒ๊ฐํ•œ๋‹ค.

๋” ๋น ๋ฅด๊ณ  ๋‹ด๋Œ€ํ•œ ๊ฐœ์„ 

๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ์€ ๋‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํ˜„์žฌ๋ฅผ ๋น„๊ตํ•œ ์•ž์„  ๋‘ ํ•ญ๋ชฉ๊ณผ ๋‹ฌ๋ฆฌ ์ด ํ•ญ๋ชฉ์€ ๋ฏธ๋ž˜์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ์ธ๋ฐ, ์–ด๋Š ์ •๋„ ๋ฏฟ์Œ์˜ ์˜์—ญ์ด๋ผ ์‚ฌ๋žŒ์— ๋”ฐ๋ผ ์˜๊ฒฌ ์ฐจ์ด๊ฐ€ ํด ์ˆ˜ ์žˆ๊ฒ ๋‹ค. ๋‚˜๋Š” React๊ฐ€ Vue.js์— ๋น„ํ•ด ์•ž์œผ๋กœ ๋” ๋น ๋ฅด๊ณ  ๋‹ด๋Œ€ํ•œ ๊ฐœ์„ ์„ ์ด๋ฃจ์–ด๋‚ผ ๊ฒƒ์ด๋ผ ๊ธฐ๋Œ€ํ•œ๋‹ค.

์ตœ๊ทผ ๊ทธ๋‹ค์ง€ ๊ธธ์ง€ ์•Š์€ ์‹œ๊ฐ„ ๋™์•ˆ React์—๋Š” Fiber๋ฅผ ๋น„๋กฏํ•ด Fragment, Portal ๋“ฑ ๊ตต์งํ•œ ๋ณ€ํ™” ๋‚ด์ง€๋Š” ๊ธฐ๋Šฅ ์ถ”๊ฐ€๊ฐ€ ์žˆ์—ˆ๋‹ค. ๋˜ํ•œ ์ƒˆ๋กœ์šด Context API, ๋ผ์ดํ”Œ์‚ฌ์ดํด ๋ฉ”์†Œ๋“œ, time slicing๊ณผ suspense ๋“ฑ ๋‹ค์–‘ํ•œ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์˜ˆ๊ณ ๋˜์–ด ์žˆ๋‹ค. ๋ชจ๋“  ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์ข‹์€ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด๋ผ๊ณ  ํ•  ์ˆœ ์—†๊ฒ ์œผ๋‚˜, ๊ทธ์™€ ๋ณ„๊ฐœ๋กœ React ํŒ€์ด ๋น ๋ฅด๊ฒŒ ์›€์ง์ด๊ณ  ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค ์ž์ฒด๋Š” ์ด๊ฒฌ์˜ ์—ฌ์ง€๊ฐ€ ์—†๋‹ค.

๋ฐ˜๋ฉด Vue.js์˜ ๋ฆด๋ฆฌ์ฆˆ๋Š” ์ƒ๋Œ€์ ์œผ๋กœ ๋Š๋ฆฌ๊ฒŒ ์ด๋ฃจ์–ด์ง€๊ณ , ์ฃผ๋กœ ๋งˆ์ด๋„ˆํ•œ ๋ณ€๊ฒฝ์‚ฌํ•ญ ์œ„์ฃผ์ธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ์ด๋Ÿฐ ์†๋„์˜ ์ฐจ์ด๋Š” ๊ฒฐ๊ตญ ํ˜„์กดํ•˜๋Š” ๋‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์ด์˜ ๊ฐ„๊ทน์ด ๋” ๋ฒŒ์–ด์ง€๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋‚ณ์„ ๊ฒƒ์ด๋‹ค. ๋น ๋ฅด๊ฒŒ ๋ณ€ํ™”ํ•˜๊ณ , ๋ฐฐ์šฐ๊ณ , ๊ทธ๋ฆฌ๊ณ  ๋ฐœ์ „ํ•ด ๊ฒฐ๊ตญ์€ ์•ž์„œ ๋‚˜๊ฐˆ React์— ๋ฒ ํŒ…ํ•˜๋Š”๊ฒŒ ๋งž๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ์ด์œ ๋‹ค.

๋งบ์œผ๋ฉฐ

์ด์ƒ ๋‚ด๊ฐ€ React๋ฅผ Vue.js๋ณด๋‹ค ๋” ์„ ํ˜ธํ•˜๋Š” ์ด์œ ๋ฅผ ์ •๋ฆฌํ•ด ๋ณด์•˜๋‹ค. ๋์œผ๋กœ ๋ง๋ถ™์ด์ž๋ฉด, ์‚ฌ์‹ค ์œ„ ๋‚ด์šฉ ์ค‘ ๋งŽ์€ ๋ถ€๋ถ„์ด ๋‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋ณด๋‹ค ๊ทผ๋ณธ์ ์ธ ์ฒ ํ•™ ์ฐจ์ด์—์„œ ํŒŒ์ƒ๋˜์—ˆ๋‹ค ์ƒ๊ฐํ•œ๋‹ค. ๋‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ถ”๊ตฌํ•˜๋Š” ๋ฐ”์— ๋Œ€ํ•ด ๋‚ด๊ฐ€ ๋ฐ›์€ ์ธ์ƒ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • React์—๋Š” Vue.js์— ๋น„ํ•ด ๋งค์ง์ด ๋œํ•˜๋‹ค. Vue.js๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ์‰ฝ๊ฒŒ ๋Š๊ปด์ง€๋Š” API๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ง์ ‘ ํ—ค๋น„ ๋ฆฌํ”„ํŒ…์„ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.
  • React๋Š” Vue.js์— ๋น„ํ•ด ํ”Œ๋ ˆ์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์— ๋” ๊ฐ€๊น๋‹ค. ์ƒˆ๋กœ์šด ๋ฌธ๋ฒ• ๋‚ด์ง€๋Š” ์ปจ๋ฒค์…˜์„ ์ •์˜ํ•˜๋Š” ๋Œ€์‹  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๊ทธ๊ฒƒ์„ ํ™œ์šฉํ•˜๋Š”๋ฐ ๋ฌด๋ฆฌ๊ฐ€ ์—†๋‹ค๋ฉด ๊ทธ๋ฆฌ ํ•œ๋‹ค.
  • React๋Š” Vue.js์— ๋น„ํ•ด ์‚ฌ์šฉ์ž ๋ฐ ์‚ฌ์šฉ์ฒ˜์— ๋Œ€ํ•ด ๋” ์ ์€ ๊ฐ€์ •์„ ํ•˜๊ณ , ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜์˜ ์„ ์–ธ์  UI ๋ Œ๋”๋ง์ด๋ผ๋Š” ๊ฐ€์žฅ ํ•ต์‹ฌ์ ์ธ ๊ธฐ๋Šฅ๊ณผ ๊ด€๋ จ๋œ ๋ถ€๋ถ„๋งŒ ์ฝ”์–ด์— ํฌํ•จํ•œ๋‹ค.

๋‘ ๊ฐ€์ง€ ๋‹ค๋ฅธ ๋ฐฉํ–ฅ ์ค‘ ๋‚˜๋Š” React์˜ ๋ฐฉํ–ฅ์— ๋” ๊ณต๊ฐํ•œ๋‹ค. ๋ฏธ๋ž˜์— ๋‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€ํ• ์ง€, ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ค ์ƒˆ๋กœ์šด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋“ฑ์žฅํ•  ์ง€ ๋ชจ๋ฅธ๋‹ค. ํ•˜์ง€๋งŒ React๊ฐ€ ์ง€๊ธˆ ๋ณด์—ฌ์ฃผ๋Š” ์ฒ ํ•™์„ ์•ž์œผ๋กœ๋„ ๊ณ ์ˆ˜ํ•˜๋ฉฐ ๊พธ์ค€ํžˆ ๋ฐœ์ „ํ•ด ๋‚˜๊ฐ„๋‹ค๋ฉด ์•ž์œผ๋กœ๋„ ๋‚˜๋Š” React๋ฅผ ์ฆ๊ฒ๊ฒŒ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค.

๋์œผ๋กœ ๋…ธํŒŒ์‹ฌ์— ๋‹ค์‹œ ๋ง๋ถ™์ด์ž๋ฉด, ๊ธ€์˜ ๋ชฉ์  ์ƒ Vue.js์˜ ๋‹จ์ ์„ ๋” ๋งŽ์ด ์–ธ๊ธ‰ํ–ˆ์ง€๋งŒ Vue.js ์—ญ์‹œ ๋ถ„๋ช… ์ข‹์€ ๋„๊ตฌ๋‹ค. ๋งŒ์•ฝ 1. ์ƒ๋Œ€์ ์œผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์— ์ต์ˆ™ํ•˜์ง€ ์•Š์€ ํŒ€์›์ด ๋งŽ์ด ์ฐธ์—ฌํ•˜๋Š” 2. ์†Œ๊ทœ๋ชจ์˜, ์˜ค๋ž˜ ์œ ์ง€๋ณด์ˆ˜ํ•˜์ง€ ์•Š์„ ํ”„๋กœ์ ํŠธ๋ผ๋ฉด Vue.js๋„ ์ข‹์€ ์„ ํƒ์ด ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค. ๋‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๊ธ์ •์ ์ธ ๊ฒฝ์Ÿ์„ ํ†ตํ•ด ํ•จ๊ป˜ ๋ฐœ์ „ํ•˜๊ธธ ๋ฐ”๋ž€๋‹ค.