React to Svelte: Mental Model
You already know how to think in components, manage state, handle events, and compose UIs. Those instincts transfer to Svelte almost one-for-one. This module is about the few places where the mental model genuinely shifts — and making sure those shifts feel obvious rather than surprising.
What transfers directly
Section titled “What transfers directly”- Component boundaries — one file, one component, composable by nesting. Same as React.
- Props flow down — parent passes data to child. Identical concept, different syntax.
- Event handlers — attach a function to an element. Identical concept, lowercase names in Svelte.
- Conditional rendering — show/hide parts of the UI based on state. Same idea, different syntax.
- List rendering — map over data to produce markup. Same idea, Svelte uses
{#each}instead of.map(). - Component lifecycle — setup and teardown logic.
$effectreplacesuseEffect. - Scoped styles — CSS that belongs to one component. React needs CSS Modules; Svelte gives this for free.
The four genuine shifts
Section titled “The four genuine shifts”| React mental model | Svelte 5 mental model |
|---|---|
| State is immutable — call a setter to update | State is mutable — assign directly, Svelte detects the change |
| Logic lives in JS; JSX is the return value | Logic and markup live in one .svelte file; no return |
| React reconciles a virtual DOM at runtime | Svelte compiles to direct DOM updates at build time |
Children are a special children prop | Children are snippets — typed, callable template fragments |
These four shifts cover 90 % of the “wait, why didn’t that work?” moments you will hit as a React developer. Every lesson in this module focuses on one of them.
Module lessons
Section titled “Module lessons”| Lesson | Concept |
|---|---|
| This page | Overview of what transfers and what shifts |
| Single-file components | .svelte structure vs JSX + CSS Modules |
| Compiler vs runtime | How Svelte eliminates the virtual DOM |
| Reactivity overview | Assignment-based reactivity vs setState |
| Scoped styles | Auto-scoped <style> vs CSS Modules |
| Same vs different | Side-by-side reference table |
A reassuring first comparison
Section titled “A reassuring first comparison”// Counter.jsximport { useState } from 'react';
export default function Counter() { const [count, setCount] = useState(0); return ( <button onClick={() => setCount(c => c + 1)}> Count: {count} </button> );}<!-- Counter.svelte --><script> let count = $state(0);</script>
<button onclick={() => count++}> Count: {count}</button>Every concept in that counter — state, an event handler, rendering a value — exists in both. The syntax is just slightly different. That pattern repeats throughout this module.