Svelte vs React: State Management Without the Ceremony
Continuing my Svelte deep-dive series, let’s talk about state management and reactivity. This is where the differences between React and Svelte can ‘feel’ much different.
React’s State Ceremony
In React, state requires a specific ritual. You declare state with useState, which gives you a getter and a setter:
const [count, setCount] = useState(0);
function increment() {
setCount(count + 1);
}
Want to update a variable? You have to call a function. You can’t just reassign count. React won’t know anything changed. This is fine once you internalize it, but it adds ceremony to what should be a simple operation.
Then there’s useEffect, which is where things get tricky. You need to understand dependency arrays, and if you get them wrong, you’re looking at infinite loops or stale data:
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]); // forget this array and enjoy your infinite loop
Some of useEffect usage is actually unnecessary and likely using it wrong. If you’re using it for data transformations, derived values from state or props, or responding to user events, you’re probably reaching for the wrong tool.
The React docs themselves will tell you that you might not need an effect. It’s a common source of bugs and confusion, especially for developers who are still building their mental model of React’s render cycle.
Svelte: Reactivity Through the Language Itself
Svelte takes a fundamentally different approach. Reactivity is baked into the language semantics. Want to declare state? Just declare a variable:
<script>
let count = $state(0);
function increment() {
count += 1;
}
</script>
<button onclick={increment}>{count}</button>
That’s it. You assign a new value, and the DOM updates. The Svelte compiler sees your assignments and automatically generates the code to update exactly the parts of the DOM that depend on that variable. No virtual DOM diffing, no setter functions, no dependency arrays to manage.
Need a derived value? Svelte has you covered with $derived:
<script>
let count = $state(0);
let doubled = $derived(count * 2);
</script>
<p>{count} doubled is {doubled}</p>
In React, you’d either compute this inline, use useMemo with a dependency array, or… if you didn’t know better reach for useEffect and a second piece of state (please don’t do this).
Svelte’s $effect rune exists for side effects like updating document.title or logging, but you should reach for it far less often than useEffect in React. The compiler handles most of what useEffect gets used for automatically.
More Svelte comparisons coming as I keep digging in. Thanks for Svelting with me.
/ javascript / svelte / React / Web development