Back to BlogOct 2025

Bridging the Gap Developers Moving Between React and Vue

A constantly evolving era.

There is no doubt that ReactJs is still the leading and most used JavaScript framework. However, I am seeing more and more React developers moving to Vue and enjoying it. Likewise, Vue developers are trying out React and finding it very similar. I believe that since the release of Vite and Vue/Nuxt 3, along with the composition API and other changes, the gap between the two frameworks is narrowing.


Common grounds between React 19 and Vue 3

(1/7) React - Creating and using a component

React components are JavaScript functions that return markup:

function MyButton() {
  return (
    <button>I'm a button</button>
  );
}

Using the component in in the same file (App.js):

function MyButton() {
  return (
    <button>
      I'm a button
    </button>
  );
}

export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
    </div>
  );
}

React projects use JSX. JSX is stricter than HTML. In React:

  • A component cannot return multiple sibling JSX elements directly.
  • You must wrap them in one parent element, e.g., <div> or a
    fragment <>...</>:
// ❌ Not allowed
return <h1>Hello</h1><p>World</p>;

// ✅ Allowed
return (
  <div>
    <h1>Hello</h1>
    <p>World</p>
  </div>
);

(2/7) React - Components in different files, parent/child, and passing props in React

In React, it's common to split components into different files. You can then import them and use them as children, passing data via props.

Example: Button component in a separate file (MyButton.js):

// MyButton.js
export default function MyButton({ label, onClick }) {
  return (
    <button onClick={onClick}>
      {label}
    </button>
  );
}

Using the Button component in a parent (App.js):

// App.js
import MyButton from './MyButton';

export default function MyApp() {
  const handleClick = () => {
    alert('Button clicked!');
  };

  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton label="Click me" onClick={handleClick} />
    </div>
  );
}

So far, we have covered:

  • Creating a simple component in React
  • Using a component in the same file as another function
  • Importing a component into a parent file
  • Passing props to a component

Let's dive deeper with a few more concepts. Then we will move the Vue.

(3/7) React - State Management in React

React uses the useState hook to manage local component state. Updating state triggers a re-render of the component.

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => setCount(count + 1);

  return (
    <div>
      <p>Current count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

Another example:

import { useState } from 'react';

export default function Greeting() {
  const [name, setName] = useState('');

  return (
    <div>
      <input
        type="text"
        placeholder="Enter your name"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      <p>Hi, {name || 'there'}!</p>
    </div>
  );
}

(4/7) React - Reactivity & Data Flow

React has a one-way data flow: data moves from parent to child via props. When state changes, React re-renders the component.

function Display({ message }) {
  return <p>{message}</p>;
}

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

  return (
    <div>
      <Display message={text} />
      <button onClick={() => setText('Hello, React!')}>Change Text</button>
    </div>
  );
}

If you observe above you might notice setText. You might be wondering what the heck is this. This is a state updater function returned by React’s useState.

useState is a React hook for creating state in functional components. It returns an array with two items:

  • text → the current value of the state.
  • setText → a function used to update the state. You can name it anything, but the convention is setStateName. For example:
const [count, setCount] = useState(0);
const [name, setName] = useState('');

(5/7) React - Conditional Rendering

In React, there is no special syntax for writing conditions. Instead, you’ll use the same techniques as you use when writing regular JavaScript code. For example, you can use an if statement to conditionally include JSX:

let content;
if (isLoggedIn) {
  content = <AdminPanel />;
} else {
  content = <LoginForm />;
}
return (
  <div>
    {content}
  </div>
);

If you observe above, see how cool is to assign to the variable let content directly your component either AdminPanel or LoginForm

Also, If you prefer more compact code, you can use the conditional ? operator. Unlike if, it works inside JSX:

<div>
  {isLoggedIn ? (
    <AdminPanel />
  ) : (
    <LoginForm />
  )}
</div>

(6/7) React - Rendering Lists

For example, let’s say you have an array of products:

const products = [
  { title: 'Cabbage', id: 1 },
  { title: 'Garlic', id: 2 },
  { title: 'Apple', id: 3 },
];

const listItems = products.map(product =>
  <li key={product.id}>
    {product.title}
  </li>
);

return (
  <ul>{listItems}</ul>
);

(7/7) React - Events

Events in React are handled via JSX attributes, and you can pass functions as props to children.

function MyButton({ label, onClick }) {
  return <button onClick={onClick}>{label}</button>;
}

export default function App() {
  const handleClick = () => alert('Button clicked!');

  return (
    <div>
      <MyButton label="Click Me" onClick={handleClick} />
    </div>
  );
}

(1/7) Vue 3 - Creating and Using Components

Vue 3 components are typically written in single-file components (SFCs) with <template>, <script>, and <style>.

<!-- MyButton.vue -->
<template>
  <button>I'm a button</button>
</template>

<script setup>

</script>

Using the component in a parent:

<!-- App.vue -->
<template>
  <div>
    <h1>Welcome to my Vue app</h1>
    <MyButton />
  </div>
</template>

<script setup>
import MyButton from './MyButton.vue';
</script>

(2/7) Components in Different Files, Parent/Child & Props

Child (MyButton.vue):

<template>
  <button @click="onClick">{{ label }}</button>
</template>

<script setup>
defineProps({
  label: String,
  onClick: Function,
});
</script>

Parent (App.vue):

<template>
  <MyButton label="Click me" :onClick="handleClick" />
</template>

<script setup>
import MyButton from './MyButton.vue';

const handleClick = () => alert('Button clicked!');
</script>

(3/7) State Management

  • ref is the reactive state.
  • v-model automatically updates the reactive variable.
<template>
  <div>
    <input v-model="name" placeholder="Enter your name" />
    <p>Hi, {{ name || 'there' }}!</p>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const name = ref('');
</script>

(4/7) Reactivity & Data Flow

Child (DisplayMessage.vue):

<template>
  <p>{{ message }}</p>
</template>

<script setup>
defineProps({
  message: String
});
</script>

Parent (App.vue):

<template>
  <DisplayMessage :message="text" />
  <button @click="text = 'Hello, Vue!'">Change Text</button>
</template>

<script setup>
import { ref } from 'vue';
import DisplayMessage from './DisplayMessage.vue';

const text = ref('Hello!');
</script>

(5/7) Conditional Rendering

Use v-if / v-else with reactive variables.

<template>
  <div>
    <AdminPanel v-if="isLoggedIn" />
    <LoginForm v-else />
  </div>
</template>

<script setup>
import { ref } from 'vue';
import AdminPanel from './AdminPanel.vue';
import LoginForm from './LoginForm.vue';

const isLoggedIn = ref(false);
</script>

(6/7) Rendering Lists

  • v-for iterates over the reactive array.
  • helps Vue track DOM elements efficiently.
<template>
  <ul>
    <li v-for="product in products" :key="product.id">
      {{ product.title }}
    </li>
  </ul>
</template>

<script setup>
const products = [
  { title: 'Cabbage', id: 1 },
  { title: 'Garlic', id: 2 },
  { title: 'Apple', id: 3 },
];
</script>

(7/7) Event Handling

Events are passed as props; parent function is invoked in child. Works naturally with reactive data.

Child (MyButton.vue):

<template>
  <button @click="onClick">{{ label }}</button>
</template>

<script setup>
defineProps({
  label: String,
  onClick: Function
});
</script>
<template>
  <MyButton label="Click Me" :onClick="handleClick" />
</template>

<script setup>
import MyButton from './MyButton.vue';

const handleClick = () => alert('Button clicked!');
</script>

TLTR - React 18 vs Vue 3: Key Differences and Similarities

1️⃣ Component Structure & Syntax

  • React: Components are functions (or classes) returning JSX. Multiple root elements require a wrapper or fragment.
  • Vue 3: Components are .vue single-file components with <template>, <script>, and <style>. Multiple root elements are allowed in templates.

2️⃣ State Management

  • React: Uses useState and useReducer for local state. Global state management can use Context API, Redux, or Zustand.
  • Vue 3: Uses reactive and ref for local state. Global state management can use Pinia or Vuex.

3️⃣ Reactivity & Data Binding

  • React: One-way data flow. Updating state triggers re-render of the component and children.
  • Vue 3: Reactive system tracks dependencies. Template updates automatically when reactive data changes. Supports both one-way and two-way binding with v-model.

4️⃣ Composition vs Hooks

  • React: Uses hooks (useEffect, useMemo, useCallback) to reuse logic and manage side effects.
  • Vue 3: Uses the Composition API (setup() function) to organize reactive logic and reuse code via composables.

5️⃣ Event Handling & Props

  • React: Props are immutable. Events are handled via JSX attributes, e.g., onClick={handleClick}.
  • Vue 3: Props are immutable. Events use v-on or @click and can be emitted to the parent using $emit.

Conclusion:
Both frameworks are highly capable and share many concepts, like components, props, and a virtual DOM. React favors JSX and hooks, while Vue 3 emphasizes templates and the Composition API. Understanding these similarities and differences makes it easier for developers to move between React and Vue with confidence.

React Official documentation: https://react.dev/

Vue Official documentation: https://vuejs.org/