Quick Start
Build your first What app in under 5 minutes. You'll learn the core concepts by building a simple counter.
Create a New Project
The fastest way to get started is with our CLI:
npm create what@latest my-app
cd my-app
npm install
npm run dev
Open http://localhost:5173 and you'll see your app running.
Project Structure
Your new project looks like this:
my-app/
├── src/
│ ├── main.jsx # App entry
│ └── styles.css # App styles
├── public/ # Optional static assets
├── index.html
├── vite.config.js
└── package.json
Your First Component
Let's build a counter. Open src/main.jsx:
import { mount, useSignal } from 'what-framework';
function App() {
const count = useSignal(0);
return (
<div>
<h1>Counter: {count()}</h1>
<button onClick={() => count.set(c => c + 1)}>
Increment
</button>
</div>
);
}
mount(<App />, '#app');
Save the file. The counter now works. Let's break down what's happening:
useSignal(0)
Creates a reactive value starting at 0. Unlike React's useState tuple, this returns a signal getter/setter pair in one primitive.
{count()} in JSX
Reading the signal in JSX subscribes that text node. When the value changes, only that node updates, not the whole component.
count.set(c => c + 1)
Updates the signal. The function receives the current value and returns the new one. The DOM updates immediately.
No Re-renders
Unlike React, What doesn't re-run your component function when state changes. It updates only the specific DOM nodes that depend on changed signals. This is called fine-grained reactivity.
Adding Computed Values
Let's add a derived value that updates automatically:
import { mount, useSignal, useComputed } from 'what-framework';
function App() {
const count = useSignal(0);
const doubled = useComputed(() => count() * 2);
return (
<div>
<h1>Count: {count()}</h1>
<p>Doubled: {doubled()}</p>
<button onClick={() => count.set(c => c + 1)}>
Increment
</button>
</div>
);
}
mount(<App />, '#app');
useComputed() creates a derived signal. It:
- Tracks which signals it reads (
countin this case) - Caches its value until dependencies change
- Updates automatically when
countchanges
Why not just const doubled = count() * 2?
In React, that works because the entire component function re-runs on every state change. In What, the component function runs once — so count() * 2 evaluates to a plain number at creation time and never updates. useComputed creates a reactive derivation that stays in sync.
For simple one-off expressions in JSX, the compiler handles it: <p>{count() * 2}</p> works directly. Use useComputed when you need the derived value in multiple places or want to pass it to child components.
Running Side Effects
Need to do something when a signal changes? Use effect():
import { mount, useSignal, effect } from 'what-framework';
function App() {
const count = useSignal(0);
// Runs immediately, then re-runs when count changes
effect(() => {
document.title = `Count: ${count()}`;
});
return (
<div>
<p>{count()}</p>
<button onClick={() => count.set(c => c + 1)}>+1</button>
</div>
);
}
Effects auto-track their dependencies — no dependency array needed. Any signal read inside the effect becomes a dependency automatically.
Next Steps
You've learned the basics. Here's where to go next: