react, vue, preact, and inferno are JavaScript libraries for building user interfaces. They all focus on creating component-based architectures where UI elements are broken down into reusable pieces. react is the most widely adopted library, using a virtual DOM and JSX syntax. vue offers a progressive framework approach with built-in reactivity and templating. preact is a lightweight alternative to React with a compatible API but a smaller footprint. inferno is a high-performance library that also mimics React's API but uses specific optimizations for speed.
react, vue, preact, and inferno all solve the same core problem โ building dynamic user interfaces with JavaScript. They share a component-based model, but they differ in how they handle updates, how you write code, and what tools surround them. Let's look at how they tackle common engineering tasks.
react uses JSX, which lets you write HTML-like syntax inside JavaScript.
// react: JSX Component
import React from 'react';
function Welcome({ name }) {
return <h1>Hello, {name}</h1>;
}
vue typically uses single-file components with a template section.
<template>, logic in <script>.<!-- vue: Single File Component -->
<template>
<h1>Hello, {{ name }}</h1>
</template>
<script setup>
defineProps({ name: String });
</script>
preact uses JSX just like React.
h implicitly via babel plugin or explicitly.// preact: JSX Component
import { h } from 'preact';
function Welcome({ name }) {
return <h1>Hello, {name}</h1>;
}
inferno also uses JSX and looks very similar to React.
createVNode calls.// inferno: JSX Component
import { createVNode } from 'inferno';
function Welcome({ name }) {
return <h1>Hello, {name}</h1>;
}
react uses Hooks like useState to manage local state.
// react: State Hook
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
vue uses a reactivity system with ref or reactive.
// vue: Reactivity
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
return { count };
}
}
// Template: <button @click="count++">{{ count }}</button>
preact supports React Hooks directly.
useState from preact/hooks.// preact: State Hook
import { useState } from 'preact/hooks';
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
inferno supports Hooks as well.
useState from inferno-hooks.// inferno: State Hook
import { useState } from 'inferno-hooks';
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
react uses a Virtual DOM to diff changes before updating the browser.
// react: Standard render
// React handles the diffing internally when state changes
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
vue uses a Virtual DOM with compiler optimizations.
<!-- vue: Optimized render -->
<!-- Compiler marks static parts to skip updates -->
<template>
<div class="static">I never change</div>
<div>{{ dynamic }}</div>
</template>
preact uses a lightweight Virtual DOM.
// preact: Standard render
// Preact handles diffing with a smaller footprint
render(<App />, document.getElementById('app'));
inferno uses a Virtual DOM with flags.
// inferno: Optimized render
// Inferno uses flags to optimize the diffing process
render(<App />, document.getElementById('app'));
react has the largest ecosystem of libraries.
// react: Ecosystem example
import { motion } from 'framer-motion'; // Popular animation lib
<motion.div animate={{ x: 100 }} />
vue has official tools for routing and state.
vue-router and pinia are maintained by the core team.// vue: Official plugins
import { createRouter } from 'vue-router';
import { createPinia } from 'pinia';
// Integrated directly into the app setup
preact is compatible with many React libraries.
preact/compat to alias React imports.// preact: Compatibility alias
// In webpack config:
resolve: { alias: { react: 'preact/compat', 'react-dom': 'preact/compat' } }
inferno has a smaller set of compatible libraries.
inferno-compat.// inferno: Compatibility
import { render } from 'inferno-compat';
// Enables some React patterns but check library support first
While the differences are clear, these libraries also share many core ideas and tools. Here are key overlaps:
// Shared concept: Props
// React/Preact/Inferno
function Button({ label }) { return <button>{label}</button>; }
// Vue
// props: ['label'], template: '<button>{{ label }}</button>'
// Shared concept: Events
// React/Preact/Inferno
<button onClick={handleClick}>Click</button>
// Vue
<button @click="handleClick">Click</button>
// Shared concept: TypeScript
// All four provide .d.ts files or built-in types
interface Props { name: string; }
// Shared concept: SSR
// React: ReactDOMServer.renderToString()
// Vue: @vue/server-renderer
// Preact: preact-render-to-string
// Inferno: inferno-server
// Shared concept: Vite Config
// All have official plugins for Vite
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react'; // or vue, preact, etc.
| Feature | Shared by All Four |
|---|---|
| Core Concept | ๐งฑ Components & Props |
| Updates | ๐ Reactive Data Binding |
| Language | ๐ ๏ธ TypeScript Support |
| Rendering | ๐ SSR Capabilities |
| Build | ๐ฆ Webpack/Vite Integration |
| Feature | react | vue | preact | inferno |
|---|---|---|---|---|
| Syntax | ๐ JSX | ๐ Templates (or JSX) | ๐ JSX | ๐ JSX |
| State | ๐ช Hooks (useState) | ๐ฎ Reactivity (ref) | ๐ช Hooks (useState) | ๐ช Hooks (useState) |
| Size | ๐ฆ Standard | ๐ฆ Standard | ๐ชถ Lightweight | ๐ชถ Lightweight |
| Ecosystem | ๐ Largest | ๐งฉ Integrated Tools | ๐ React Compatible | ๐ง Specialized |
| Optimization | โ๏ธ Fiber Reconciliation | ๐ Compiler Hoisting | โก Fast Diffing | ๐๏ธ VNode Flags |
react is the industry standard ๐ข โ best for teams that want maximum library support and hiring flexibility. Ideal for large-scale apps where ecosystem maturity matters most.
vue is the balanced framework โ๏ธ โ perfect for developers who want clear structure with built-in routing and state tools. Great for rapid development and clean code organization.
preact is the lightweight swap ๐ชถ โ use when you want React features but need to save bandwidth. Best for widgets, embedded tools, or slow network environments.
inferno is the performance specialist ๐๏ธ โ choose when you need every millisecond of render time and can manage a smaller community. Fits high-frequency trading dashboards or complex data viz.
Final Thought: All four tools can build excellent applications. Your choice should depend on your team's skills, project size, and performance needs โ not just hype.
Choose react if you need the largest ecosystem, extensive third-party support, and a standard skill set for hiring. It is the safest bet for long-term enterprise projects where community support and library availability are critical factors.
Choose preact if you need React compatibility but have strict bundle size constraints. It works well for widgets, embedded apps, or performance-critical sections where every kilobyte counts without changing your React code.
Choose vue if you prefer a framework that includes routing and state management solutions out of the box. It is ideal for teams that want a gentle learning curve with clear separation of concerns between logic, template, and styles.
Choose inferno if you have specific high-performance requirements and prefer a React-like API without the React overhead. It suits specialized applications where you need fine-grained control over rendering cycles and virtual DOM flags.
reactReact is a JavaScript library for creating user interfaces.
The react package contains only the functionality necessary to define React components. It is typically used together with a React renderer like react-dom for the web, or react-native for the native environments.
Note: by default, React will be in development mode. The development version includes extra warnings about common mistakes, whereas the production version includes extra performance optimizations and strips all error messages. Don't forget to use the production build when deploying your application.
import { useState } from 'react';
import { createRoot } from 'react-dom/client';
function Counter() {
const [count, setCount] = useState(0);
return (
<>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</>
);
}
const root = createRoot(document.getElementById('root'));
root.render(<Counter />);