Menu

React vs Vue: Differences With Side by Side Code

React and Vue are both JavaScript tools for building user interfaces from components. They differ in markup (JSX vs templates), in how they react to changes (immutable state and re-renders vs mutable reactive refs), and in how much of the ecosystem is official.

This page includes runnable editors - edit, run, and see output instantly.

React and Vue are both JavaScript tools for building user interfaces from components (React calls itself a library, Vue a progressive framework), and they share most ideas: props down, events up, reactive state, a virtual DOM. The practical differences are that React writes markup in JSX and expects state to be replaced with a setter, while Vue writes markup in HTML templates inside single-file components and lets you change reactive values directly. Here is a counter in React:

And the same counter as a Vue single-file component (Counter.vue):

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

const count = ref(0);
</script>

<template>
    <button @click="count++">Clicked {{ count }} times</button>
</template>

useState(0) becomes ref(0), onClick becomes @click, and {count} becomes {{ count }}. The visible difference is count++: Vue lets you change the value in place, and its reactivity system notices. React needs setCount because it only re-renders when you hand it a new value.

JSX vs single-file components

A React component is a JavaScript function that returns JSX. Conditions are && or a ternary, lists are .map(), and styles come from whatever you choose (CSS files, CSS modules, a utility framework).

A Vue component is usually a .vue file with three blocks: <script setup> for logic, <template> for markup, and an optional <style scoped> whose CSS applies only to that component. Templates use directives: v-if, v-for, v-model for two-way input binding, :prop to bind a value and @event to listen. Templates keep markup readable for anyone who knows HTML; JSX gives you the whole of JavaScript in the markup. Vue can use JSX too and React cannot use templates, but most code in each follows its default.

Here is a filtered list, the second feature to compare.

Try typing xyz to see the empty message, then delete it. The Vue version:

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

const fruits = ['Apple', 'Banana', 'Cherry', 'Grape', 'Mango', 'Peach'];
const query = ref('');

const visible = computed(() =>
    fruits.filter((f) => f.toLowerCase().includes(query.value.toLowerCase()))
);
</script>

<template>
    <input v-model="query" placeholder="Filter fruit" />
    <ul>
        <li v-for="fruit in visible" :key="fruit">{{ fruit }}</li>
        <li v-if="visible.length === 0">No match</li>
    </ul>
</template>

v-model replaces the value plus onChange pair, and computed replaces the plain variable. In React, visible is recomputed on every render because the component function runs again; in Vue, computed caches it and recomputes only when query changes. Both use a key to tell list items apart.

The reactivity model

This is the deepest difference between the two.

React: immutable state and re-renders. State is a snapshot. You call a setter with a new value, React runs the component function again, compares the new JSX with the old, and updates the DOM. React compares values with Object.is, so changing an object or array in place and passing the same one back looks like no change at all.

Click "push() in place" and nothing changes on screen, because the array is the same object. Then click "New array": the render shows pushed too, because the earlier mutation really happened, React just had no reason to look. The useState page covers this pattern in depth.

Vue: mutable reactive values. A ref or reactive object records who reads it (a ref through its .value getter, a reactive object through a proxy). When you write to it, Vue knows exactly which computed values, watchers and template parts depend on it and updates only those. In Vue, items.value.push('pushed') updates the screen. You write less ceremony, and you give up the guarantee that a value never changes under you.

Neither model is faster in a way that matters for typical apps. React may run more component code per change and relies on memoization (by hand, or through the React Compiler) to skip work; Vue tracks dependencies at runtime so it skips that work by default.

Composition API vs hooks

Vue 3's Composition API and React hooks solve the same problem: putting related state and logic together and reusing it across components. Vue calls the reusable functions composables (useMouse()), React calls them custom hooks (useMouse()). The rules differ because of when the code runs.

  • When it runs. A Vue setup runs once when the component is created. A React component function runs on every render, and the hooks inside it run with it.
  • Order rules. React matches hooks by call order, so you cannot call them inside conditions or loops. Vue has no such rule for ref and computed, because setup runs once.
  • Dependencies. React effects and memos list their dependencies in an array you maintain. Vue's watchEffect and computed track what they read automatically.
  • Stale values. A React callback can capture an old state value from an earlier render (the classic setInterval bug). A Vue callback reads count.value at call time and always sees the current value.

React's model makes every render a pure function of props and state, which is easy to test and reason about. Vue's model removes a class of bugs around dependency arrays. Developers who know one usually pick up the other quickly.

Ecosystem

ReactVue
MarkupJSXHTML templates in .vue files (JSX optional)
State updatesReplace with a setter, then re-renderChange a reactive value, dependents update
Logic reuseCustom hooksComposables
Derived valuesComputed during render, useMemocomputed (cached)
Two-way input bindingvalue plus onChangev-model
Scoped CSSNot built in (CSS modules, libraries)<style scoped> built in
RoutingReact Router, TanStack Router, frameworksVue Router (official)
Global stateContext, Zustand, Redux ToolkitPinia (official)
Full-stack frameworkNext.js, React Router framework modeNuxt
Mobile appsReact NativeNo official option (Capacitor, NativeScript-Vue)
Build toolVite or a frameworkVite
Maintained byMeta and the communityAn independent core team and the community

The pattern in that table: Vue's core team maintains the router, the store and the devtools together, so a Vue project has an obvious default for each. React leaves those to the community, which gives you more options and more decisions. Vite, the usual build tool for new projects in both, was started by Vue's creator.

Learning curve

Vue is often the gentler start. Templates read like the HTML you already know, v-model removes the controlled input boilerplate, and a reactive value updates the screen when you change it. React asks for JSX and for the immutable update habit up front, and the JSX page is the first thing most people need.

After the basics, the gap narrows. Vue adds its own concepts (refs vs reactive objects, .value in scripts but not in templates, watchers), and React adds effects, memoization and the rules of hooks. Job listings in your area are a more useful tiebreaker than syntax.

When to pick which

Pick React when:

  • You want a wide choice of community libraries and components, or you plan to build native mobile apps with React Native.
  • You like keeping logic and markup in one JavaScript function and want a framework such as Next.js.
  • Your team values explicit, immutable updates that make each render easy to trace.

Pick Vue when:

  • You want official, matching tools for routing and state and fewer decisions to make.
  • Your team includes designers or back-end developers who are comfortable with HTML templates.
  • You are adding interactivity to existing server-rendered pages: Vue can be dropped into a page from a script tag and grow from there.

Both are mature and used in production by companies of every size, and the concepts you learn in one (components, props, derived state, keyed lists) carry straight over to the other.

Frequently Asked Questions

Is Vue easier than React?

Many beginners find Vue easier at first, because templates look like plain HTML and changing a reactive value (count.value++) updates the screen with no setter. React asks you to learn JSX and the rule that state must be replaced, not changed. After the first weeks the difficulty is similar.

Is React or Vue better?

Neither wins in general. React leaves routing and state to community libraries and has React Native for mobile. Vue has an official router, store and devtools maintained together, and templates many people find easier to read. Pick the one your team or job market uses.

What is the difference between Vue's Composition API and React hooks?

Both group stateful logic into reusable functions. A Vue setup runs once per component and tracks dependencies automatically, so there are no dependency arrays and no stale closures. A React component function runs on every render, so hooks must be called in the same order every time and effects list their dependencies.

Does Vue use JSX?

Vue supports JSX through a plugin, but most Vue code uses HTML templates in single-file components (.vue files). React uses JSX almost everywhere.

What is the Vue equivalent of Next.js?

Nuxt. Like Next.js for React, it adds file-based routing, server rendering, static generation and server routes on top of Vue.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED