본문으로 건너뛰기
Previous
Next
Preact Complete Guide | Fast 3KB React Alternative

Preact Complete Guide | Fast 3KB React Alternative

Preact Complete Guide | Fast 3KB React Alternative

이 글의 핵심

Preact is a fast 3KB alternative to React with the same modern API. It's perfect for performance-critical applications and works with most React libraries.

Introduction

Preact is a fast 3KB alternative to React with the same modern API. It’s not a reimplementation of React, but a fresh take on the Virtual DOM with a focus on performance and size.

Created by Jason Miller (Google Chrome team member, creator of wmr and many performance tools), Preact represents what React would look like if it prioritized size and speed above all else.

Why Preact Matters

The performance impact of bundle size:

  • Preact: 3KB gzipped (13x smaller than React)
  • React: 40KB gzipped (not including React DOM)
  • On 3G networks: 200ms faster initial load with Preact

Real-world adoption:

  • Uber.com ??migrated from React to Preact, improved TTI by 50%
  • Etsy ??uses Preact for embedded widgets on seller pages
  • Housing.com ??switched to Preact, reduced JS bundle from 200KB to 100KB
  • ~7 million weekly npm downloads (widely used for performance-critical sites)

Production use cases where Preact excels:

  • Embedded widgets ??third-party widgets that load on other sites (ads, chat, analytics)
  • E-commerce product pages ??every 100ms load time = 1% conversion increase
  • Progressive Web Apps ??offline-first apps where bundle size matters
  • Mobile-first sites ??emerging markets with slow networks

When to choose Preact:

  • Performance is critical (e-commerce, mobile-first)
  • Building embeddable widgets for third-party sites
  • Bundle size matters (need <5KB base framework)
  • Already using React patterns, want instant performance win

When to use React instead:

  • Need React Native for mobile apps
  • Using many React-specific libraries (check compatibility)
  • Team is React-expert and performance is “good enough”
  • Corporate requirement (React has Facebook backing)

React vs Preact

React (40KB):

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

Preact (3KB):

import { h } from 'preact';
import { useState } from 'preact/hooks';

function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

Almost identical!

1. Installation

New Project with Vite

npm create vite@latest my-app -- --template preact-ts
cd my-app
npm install
npm run dev

Add to Existing Project

npm install preact

2. Core Concepts

JSX and h()

import { h } from 'preact';

// JSX (recommended)
const element = <div>Hello</div>;

// h() function (JSX compiles to this)
const element = h('div', null, 'Hello');

Components

import { h } from 'preact';

// Function component
function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

// With TypeScript
interface GreetingProps {
  name: string;
}

function Greeting({ name }: GreetingProps) {
  return <h1>Hello, {name}!</h1>;
}

Props and Children

function Card({ title, children }) {
  return (
    <div class="card">
      <h2>{title}</h2>
      <div>{children}</div>
    </div>
  );
}

// Usage
<Card title="My Card">
  <p>Card content</p>
</Card>

3. Hooks

useState

import { useState } from 'preact/hooks';

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={() => setCount(c => c + 1)}>Increment (updater)</button>
    </div>
  );
}

useEffect

import { useEffect } from 'preact/hooks';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(setUser);
  }, [userId]); // Re-run when userId changes
  
  return <div>{user?.name}</div>;
}

useMemo

import { useMemo } from 'preact/hooks';

function ExpensiveList({ items, filter }) {
  const filtered = useMemo(() => {
    console.log('Filtering...');
    return items.filter(item => item.includes(filter));
  }, [items, filter]);
  
  return (
    <ul>
      {filtered.map(item => <li key={item}>{item}</li>)}
    </ul>
  );
}

useCallback

import { useCallback } from 'preact/hooks';

function TodoList({ todos }) {
  const [filter, setFilter] = useState('');
  
  const handleFilter = useCallback((e) => {
    setFilter(e.target.value);
  }, []);
  
  return (
    <div>
      <input onInput={handleFilter} />
      {/* TodoItem won't re-render if handleFilter doesn't change */}
    </div>
  );
}

useRef

import { useRef } from 'preact/hooks';

function TextInput() {
  const inputRef = useRef(null);
  
  const focusInput = () => {
    inputRef.current?.focus();
  };
  
  return (
    <div>
      <input ref={inputRef} />
      <button onClick={focusInput}>Focus</button>
    </div>
  );
}

4. React Compatibility

Using preact/compat

npm install preact

vite.config.ts:

import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';

export default defineConfig({
  plugins: [preact()],
  resolve: {
    alias: {
      react: 'preact/compat',
      'react-dom': 'preact/compat',
    },
  },
});

Now you can use React libraries!

// Works with Preact via compat
import { useState } from 'react';
import { createPortal } from 'react-dom';

5. Signals (Preact’s Secret Weapon)

npm install @preact/signals
import { signal, computed } from '@preact/signals';

const count = signal(0);
const doubled = computed(() => count.value * 2);

function Counter() {
  // No useState needed! Signals auto-update
  return (
    <div>
      <p>Count: {count}</p>
      <p>Doubled: {doubled}</p>
      <button onClick={() => count.value++}>Increment</button>
    </div>
  );
}

Why Signals?

  • No re-renders needed
  • Automatically optimized
  • Global state without context

6. Routing

npm install preact-router
import { Router, Route } from 'preact-router';

function App() {
  return (
    <Router>
      <Home path="/" />
      <Profile path="/profile/:user" />
      <NotFound default />
    </Router>
  );
}

function Profile({ user }) {
  return <h1>Profile: {user}</h1>;
}

7. Server-Side Rendering

import { render } from 'preact-render-to-string';

const html = render(<App />);
console.log(html); // <div>...</div>

8. Performance Tips

1. Use Signals for Global State

// Global signal (no context needed)
import { signal } from '@preact/signals';

export const user = signal(null);

// Use anywhere
function Header() {
  return <div>Welcome, {user.value?.name}</div>;
}

2. Memoize Components

import { memo } from 'preact/compat';

const ExpensiveComponent = memo(({ data }) => {
  // Only re-renders when data changes
  return <div>{data}</div>;
});

3. Lazy Load Components

import { lazy, Suspense } from 'preact/compat';

const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <HeavyComponent />
    </Suspense>
  );
}

9. Differences from React

class vs className

// Preact: use "class" (HTML standard)
<div class="container">Hello</div>

// React: use "className"
<div className="container">Hello</div>

// Both work in Preact!

Event Naming

// Preact: lowercase events work
<input onchange={handleChange} />

// React: camelCase only
<input onChange={handleChange} />

// Both work in Preact!

No Synthetic Events

Preact uses native browser events (faster!):

function handleClick(e) {
  // e is a native Event, not SyntheticEvent
  console.log(e.target);
}

10. Real-World Example

Todo App with Signals

import { signal, computed } from '@preact/signals';

const todos = signal([
  { id: 1, text: 'Learn Preact', done: false },
]);
const filter = signal('all');

const filteredTodos = computed(() => {
  if (filter.value === 'all') return todos.value;
  return todos.value.filter(t => 
    filter.value === 'done' ? t.done : !t.done
  );
});

function TodoApp() {
  const addTodo = (text) => {
    todos.value = [...todos.value, {
      id: Date.now(),
      text,
      done: false,
    }];
  };
  
  const toggleTodo = (id) => {
    todos.value = todos.value.map(t =>
      t.id === id ? { ...t, done: !t.done } : t
    );
  };
  
  return (
    <div>
      <input onKeyUp={(e) => {
        if (e.key === 'Enter') {
          addTodo(e.target.value);
          e.target.value = '';
        }
      }} />
      
      <div>
        <button onClick={() => filter.value = 'all'}>All</button>
        <button onClick={() => filter.value = 'active'}>Active</button>
        <button onClick={() => filter.value = 'done'}>Done</button>
      </div>
      
      <ul>
        {filteredTodos.value.map(todo => (
          <li key={todo.id}>
            <input
              type="checkbox"
              checked={todo.done}
              onChange={() => toggleTodo(todo.id)}
            />
            {todo.text}
          </li>
        ))}
      </ul>
    </div>
  );
}

11. Bundle Size Comparison

LibrarySize (gzipped)Load Time (3G)
Preact3KB60ms
Vue34KB680ms
React40KB800ms

Summary

Preact is the perfect React alternative for performance:

  • 3KB vs React’s 40KB (13x smaller)
  • Same API - React knowledge transfers
  • Signals for ultra-fast state
  • Compatible with most React libraries
  • Faster rendering and smaller bundles

Key Takeaways:

  1. Almost identical API to React
  2. Use preact/compat for React libraries
  3. Signals eliminate re-renders
  4. Use class instead of className
  5. Perfect for performance-critical apps

Next Steps:

  • Learn [React 18](/en/blog/react-18-deep-dive/
  • Try [Solid.js](/en/blog/solid-js-complete-guide/
  • Build with [Vite](/en/blog/vite-complete-guide/

Resources:


?�주 묻는 질문 (FAQ)

Q. ???�용???�무?�서 ?�제 ?�나??

A. Complete Preact guide for building fast web apps. Learn the lightweight React alternative with the same API, hooks, and ???�무?�서????본문???�제?� ?�택 가?�드�?참고???�용?�면 ?�니??

Q. ?�행?�로 ?�으�?좋�? 글?�?

A. �?글 ?�단???�전 글 ?�는 관??글 링크�??�라가�??�서?��?배울 ???�습?�다. C++ ?�리�?목차?�서 ?�체 ?�름???�인?????�습?�다.

Q. ??깊이 공�??�려�?

A. cppreference?� ?�당 ?�이브러�?공식 문서�?참고?�세?? 글 말�???참고 ?�료 링크???�용?�면 좋습?�다.


같이 보면 좋�? 글 (?��? 링크)

??주제?� ?�결?�는 ?�른 글?�니??

  • [Lit Complete Guide | Fast Web Components Library](/en/blog/lit-complete-guide/
  • [Zustand Complete Guide | Minimal React State](/en/blog/zustand-complete-guide/
  • [Alpine.js Complete Guide | Lightweight JavaScript Framework](/en/blog/alpine-js-complete-guide/

??글?�서 ?�루???�워??(관??검?�어)

Preact, React, JavaScript, Performance, Frontend, Lightweight ?�으�?검?�하?�면 ??글???��????�니??