DEV Community

Cover image for First Impressions of Vue3: Comparing with React through a Todo App
SeongKuk Han
SeongKuk Han

Posted on

First Impressions of Vue3: Comparing with React through a Todo App

If you seek job opportunities, you will see three frontend frameworks dominate the frontend world.

  • React
  • Angular
  • Vue

React

React is the most used frontend library in frontend development. Based on my experience, once you know the principles of React, it is easy to use. Unlike the other frameworks, you may feel you're dealing with Javascript more than HTML. You also may find things strange like the rendering process and a property name className.

Angular

Since I haven't had experience working with Angular, I don't have any strong opinions about it. However, from what I have heard about Angular from youtube videos and articles I read, Angular is quite a big framework and has almost everything we need to develop a frontend project. I wouldn't mind working with Angular if I have to, but, frequent version changes and coming with many features don't sound intriguing to me. Even though, I admit that there's a lot to learn from its structures as a frontend developer.

Vue

According to 2023 StateOfJS Survey), Vue is the second most used frontend framework. It has surpassed Angular last year. Easy to use and high performance first come to my mind when I think of Vue.


During the time applying for jobs for the last couple of months, I thought it would be good to know a little bit about Vue to expand job opportunities. Last year, when I tried SolidJS one time. I learned a lot and also, I got to get a better understanding of React.

I will compare things that I found different between Vue and React while building a todo app using Vue. I spent only some hours on it, therefore, something might not sound right. If you find anything that doesn't sound right, please let me know in the comment below. Thank you very much.


App Preview

Home Page

Todo Page

This is the todo app.

I created components using Single File Component, and I utilized json-server for implementing an API server.


Comparison

Properties

React

import React from 'react';

function TodoItem({ title, desc, done }: { title: string, desc:string, done: boolean }) {
  return (
    <>
      <h2>{title}</h2>
      <p>{desc}</p>
      <span>{done ? 'checked' : 'unchecked'}</span>
    </>
  )
}

export default function App() {
  return <TodoItem title="title" desc="desc" done={true} />;
}
Enter fullscreen mode Exit fullscreen mode

Vue

// App
<script setup>
import TodoItem from './TodoItem.vue'
</script>

<template>
  <TodoItem title="title" desc="desc" :done="true" />
</template>

// TodoItem
<script setup lang="ts">
const props = defineProps<{
  title: string
  desc: string
  done: boolean
}>()
</script>

<template>
  <h2>{{ props.title }}</h2>
  <p>{{ props.desc }}</p>
  <span>{{ props.done ? 'checked' : 'unchecked' }}</span>
</template>
Enter fullscreen mode Exit fullscreen mode

While React components get properties from the parameters, in Vue3, components receive properties from the defineProps function in non-setup script components.

You can define type definition for properties using generic type arguments like in React, but Vue 3 also provides an additional way to define prop types, the runtime props option.

Passing properties to the component is the same in both React and Vue. They are passed as attributes with the properties' names and the values.

There is a difference when you want to pass variables in javascript.

In React, you can inject javascript code within curly brackets {}. In Vue, you use v-bind. Here, in the example,: is used, which is a shorthand of v-bind.

I'm not used to Vue yet though, for me, The way React uses makes more sense, curly brackets to inject js code.


Children

React

import React from 'react';

function Child({ children }: { children: React.ReactNode }) {
  return (
    <>
      {children}
    </>
  )
}

export default function App() {
  return (
    <Child>
      <h1>Child Component</h1>
    </Child>
  );
}
Enter fullscreen mode Exit fullscreen mode

Vue

// App
<script setup>
import Child from './Child.vue'
</script>

<template>
  <Child>
    <h1>Child Component</h1>
  </Child>
</template>

// Child
<template>
  <slot />
</template>
Enter fullscreen mode Exit fullscreen mode

To pass the HTML code written in the component, React uses the prop, children while Vue uses the slot tag. In Vue, it is more convenient as you don't need to mention to use it.


Custom Events

React

import React from 'react';

function Child({ onClick }: { onClick: (msg: string) => void }) {
  return (
    <div onClick={() => onClick("message")}>Child</div>
  )
}

export default function App() {
  return <Child onClick={(msg) => console.log(msg)} />;
}
Enter fullscreen mode Exit fullscreen mode

Vue

// App
<script setup>
import Child from './Child.vue'
</script>

<template>
  <Child @click="(msg) => console.log(msg)" />
</template>

// Child
<script setup lang="ts">
const emit = defineEmits<{
  (e: 'click', msg: string): void
}>()
</script>
<template>
  <div @click="emit('click', 'message')">Child</div>
</template>
Enter fullscreen mode Exit fullscreen mode

In React, custom events are delivered via props, so defining the type of custom events is the same as the other props.

In Vue, you use the built-in $emit method to implement custom events. However, to explicitly declare the events, you use the defineEmits function.

I like the idea of separating events from properties. The way I see it, It seems clearer than mixing up all the properties in one place. However, In my opinion, Passing altogether is simpler than separating them.

By the way, @ is a shorthand of v-on.


Data Binding

React

import React, { useState } from 'react';

export default function App() {
  const [text, setText] = useState('');

  return (
    <>
      <input value={text} onChange={e => setText(e.target.value)}  />
      <h1>{text}</h1>
    </>
  ); 
}
Enter fullscreen mode Exit fullscreen mode

Vue

<script setup lang="ts">
  import { ref } from 'vue'
  const text = ref('')
</script>

<template>
  <input v-model="text" />
  <h1>{{ text }}</h1>
</template>
Enter fullscreen mode Exit fullscreen mode

As React doesn't provide a data-binding feature, we must pass handlers to update states. On the other hand, Vue provides a data-binding. So, we don't need to implement the logic by ourselves to update states.

However, when we work on a React project, we likely use form libraries to handle form inputs like react-hook-form, and it also provides various features to manage form inputs efficiently such as error handling, validation, and so on.


Directives

React

  {
    todos.map((todo) => (
      <Todo 
        key={todo.id}
        title={todo.title}
        desc={todo.desc}
        done={todo.done}
        onDone={handleDone(todo.id)}
        onEdit={handleEdit(todo.id)}
        onDelete={handleDelete(todo.id)}
      />
    ))
  }
Enter fullscreen mode Exit fullscreen mode
    {
      todos ? 
      <TodoList
        todos="todos"
      /> :
      <i v-else class="pi pi-spinner loading"></i>
    }
Enter fullscreen mode Exit fullscreen mode

Vue

  <Todo
    v-for="todo in props.todos"
    :key="todo.id"
    :title="todo.title"
    :desc="todo.desc"
    :done="todo.done"
    @done="emit('done', todo.id)"
    @edit="emit('edit', todo.id)"
    @delete="emit('delete', todo.id)"
  />
Enter fullscreen mode Exit fullscreen mode
    <TodoList
      v-if="todos"
      :todos="todos"
    />
    <i v-else class="pi pi-spinner loading"></i>
Enter fullscreen mode Exit fullscreen mode

SolidJS also provides control-flow components such as For and Show that I found it would be good to have in React. Although that stuff can be componentized the same way in React, since it's not standard, many use javascript like map and ternary operator.

In Vue, there are directives like v-for, v-if, and v-show. As they' are provided by the frontend framework, you don't need to worry about anything else besides knowing how to use them from the docs. For instance, In React, to implement conditional rendering, you might have to choose among options, for, if, switch, and ternary operator. I think this is pretty cool, those are provided at the framework level.


Update States

To reflect data changes onto the screen, Vue uses Proxy API, by using it, it knows exactly where it needs to be updated.

In React, to update states, you use setState and it causes re-render.


Conclusion

Working with Vue feels like I work in HTML in template engines. As It provides a variety of directives, I didn't write any JS such as for list rendering and conditional rendering. Proxy API was also an interesting part. Experience with SolidJS got me a quick understanding of it. As a frontend developer who has mostly been working with React, this is kind of a new world. Thinking of it, updates places where need to be updated sounds obviously better than executeing a whole component function. This is why many React projects leak performance. However, React has solutions useCallback, useMemo, memo and stuff like that to prevent this and React compiler is in an experimental stage now. React has its own principles. While I admit amazing features I could use in Vue out of the box, I like React's simplicity, or maybe I just got used to it.

Knowing how each library/framework works widened my eyes. If you have experience with only one framework, I strongly recommend trying other frontend libraries/frameworks. It may be helpful to get an understanding of the frontend library/framework better that you're actively using.

THanks a lot, you can see the full code https://github.com/hsk-kr/vue-todo.

Happy Coding!

Top comments (0)