사실 나는 React 개발자에 가까운 형태로 프론트엔드 개발을 진행해왔고, 이를 쫓아가기 바쁘게 개발해왔는데,
문득 JavaScript를 사용하는 프론트엔드 개발자라면, React외에도 Svelte나 Vue, Angular에 대해서 들어봤을거다.
처음 프론트엔드 개발을 할때 Vue로 시작하는게 배우기 쉽고 이후에 React로 넘어가면 좋다고 들었지만, 그래도 시장상황상 취업하기 React가 좀 더 수월하다고 판단했다. 그렇지만, 개발을 공부하고 알아갈수록 그런 문제가 아니라, 어떤 형태로든 개발하는 원리적인 부분이나 파고 들어가고 이해하는 부분은 크게 다르지 않다는걸 알게 됐고, 결국 JavaScript를 알게 되면, 자연스럽게 새로운 형태에 라이브러리나 프레임워크도 유연하게 받아들이는 사고가 길러진다는것을 다들 연차가 쌓일수록 느끼는 부분일거다.
React와 다른 프론트엔드 개발들은 어떤 형태로 개발을 만들수 있고 왜 한 축을 담당할 정도의 프레임워크인지 알아보려 한다.
Vue는 React에 비해 상대적으로 프레임워크 특성이 강해 비교적 형태를 유도하는 느낌이 들었다.
직접 설치해서 간단한 TodoList까지 만들어 봤다.
나는 우선 bun 패키지 매니저를 사용하고 있기 때문에, 해당 설치 기준으로 기록했다.
bun create를 사용하여 vue를 생성해주면 다음과 같이 프로젝트를 생성할 수 잇다.
CRA 만드는것과 매우 유사했다.
이후 코드를 생성하면 다음과 같이 페이지가 나온다.
굉장히 독특하다고 생각이 든건 자체적으로 devtools와 해당 컴포넌트를 쫓아갈수 있는 툴이 보인다.
코드 디렉토리를 보면 React처럼 유사하게 구성되어있고, 이에 App.vue 파일을 살펴봤다.
// App.vue
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue';
import TheWelcome from './components/TheWelcome.vue';
</script>
<template>
<header>
<WelcomeItem>
<HelloWorld />
</WelcomeItem>
</header>
<div type>
<TheWelcome />
</div>
</template>
<style scoped>
header {
line-height: 1.5;
}
.logo {
display: block;
margin: 0 auto 2rem;
}
@media (min-width: 1024px) {
header {
display: flex;
place-items: center;
padding-right: calc(var(--section-gap) / 2);
}
.logo {
margin: 0 2rem 0 0;
}
header .wrapper {
display: flex;
place-items: flex-start;
flex-wrap: wrap;
}
}
</style>
vue는 script template style이 명확하게 나눠 한 vue 파일에서 관리하는 형태로 코드구성이 되어있고,
이는 프레임워크 특성이 잘 드러나있고, 상당히 직관적이라고 느껴졌다.
간단한 TodoList 작성으로 상태관리나, 컴포넌트 작성을 어떤식으로 진행해나가는지 알아봤다.
<template>
<div class="container">
<h1>할 일 목록</h1>
<div class="input-wrap">
<input v-model="newTodo" @keyup.enter="addTodo" placeholder="할 일 입력" />
<button @click="addTodo">추가</button>
</div>
<ul>
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" :checked="todo.completed" @change="toggleTodo(todo.id)" />
<span :class="{ done: todo.completed }">{{ todo.text }}</span>
<button @click="removeTodo(todo.id)">삭제</button>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
newTodo: '',
todos: []
};
},
methods: {
addTodo() {
if (this.newTodo.trim()) {
this.todos.push({ id: Date.now(), text: this.newTodo, completed: false });
this.newTodo = '';
}
},
toggleTodo(id) {
const todo = this.todos.find(todo => todo.id === id);
if (todo) {
todo.completed = !todo.completed;
}
},
removeTodo(id) {
this.todos = this.todos.filter(todo => todo.id !== id);
}
}
};
</script>
<style scoped>
/* 스타일은 동일 */
</style>
v-model으로 양방향 바인딩이 가능했고, keyup이나 @click 같은 태그들이 React에서 onClick 역할을 하는듯 했다.
script 태그에서는 동적인 처리를 담당하는 형태로 구성한다.
Vue3 들어서 도입된 기능인데 코드 재사용성과 가독성을 높이는 형태로 작성한다고 한다.
앞서 작성했던 vue 코드를 다시 작성하였다.
// ../components/TodoList.vue
<template>
<div class="container">
<h1>할 일 목록</h1>
<div class="input-wrap">
<input v-model="newTodo" @keyup.enter="addTodo" placeholder="할 일 입력" />
<button @click="addTodo">추가</button>
</div>
<ul>
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" :checked="todo.completed" @change="toggleTodo(todo.id)" />
<span :class="{ done: todo.completed }">{{ todo.text }}</span>
<button @click="removeTodo(todo.id)">삭제</button>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import { useTodos } from "../composables/useTodos";
const { todos, newTodo, addTodo, toggleTodo, removeTodo } = useTodos();
</script>
<style scoped>
/* 스타일은 동일 */
</style>
React에서 사용했던 상태관리 Zustand와 매우 유사하게 작성한다는 느낌을 받았고, 재사용성에 염두해 두는 로직처리가 가능했다.
확실히 가독성이 많이 올라간 형태다.
// ../composables/useTodos.ts
import { ref } from "vue";
import { useStore } from "vuex";
export function useTodos() {
const store = useStore();
const newTodo = ref("");
const addTodo = () => {
if (newTodo.value.trim()) {
store.commit("addTodo", newTodo.value);
newTodo.value = "";
}
};
const toggleTodo = (id: number) => {
store.commit("toggleTodo", id);
};
const removeTodo = (id: number) => {
store.commit("removeTodo", id);
};
return {
todos: store.state.todos,
newTodo,
addTodo,
toggleTodo,
removeTodo,
};
}
캡슐화된 메서드들로 바로 직관적으로 관리가 가능했다.
Vuex는 Vue에서 사용하는 상태관리로 게터나 뮤테이션 액션을 포함해서 복잡도를 줄여주고, 우리가 알고 있는 상태관리 역할을 해준다.
import { createStore, Store } from "vuex";
interface Todo {
id: number;
text: string;
completed: boolean;
}
interface State {
todos: Todo[];
}
export const store = createStore<State>({
state: {
todos: [],
},
mutations: {
addTodo(state, text: string) {
state.todos.push({
id: Date.now(),
text,
completed: false,
});
},
removeTodo(state, id: number) {
state.todos = state.todos.filter((todo) => todo.id !== id);
},
toggleTodo(state, id: number) {
const todo = state.todos.find((todo) => todo.id === id);
if (todo) {
todo.completed = !todo.completed;
}
},
},
});
Vuex는 중앙에서 집중식 저장소를 사용하여, 상태를 관리하는 형태로 되어있다. Vuex에서 상태 변경을 하려면 뮤테이션을 사용하는 유도를 하지만, React는 방법이 다양해서 유연한 부분이 있다.
React는 라이브러리에 따라 특징이나 처리방법이 다 다르지만, Vue는 어느정도 관리하는 법을 강제하는 부분이 있어, 작성방식에서 일관적인 부분을 가진다.
Vue를 살펴보면서 느낀건 프로젝트 성향이나 상황에 따라 어떤 개발자와 함께 하는가에도 취향이며, 어떤 회사에서 사용하느냐에도 결정되는 부분이 있고 확실히 작성 스타일이 유연하고 많은 방법을 가진 React보다는 Vue가 직관적이고 일관성을 가진 부분이 있지만, 작성에서 조금 유연성이 떨어질 수도 있을거란 생각은 아쉬운부분이 있다.
뭔가 이게 더 좋다라기 보단 취향이나 스타일 차이라 향후에는 Vue로도 개발을 할 수 있고 차이점을 알게되어 더 강점으로 작용하는 부분이 있다면 차용할 계획을 가지면 어떨까 싶다.