levelorbit
Writing

Different models of React and Svelte

In 2024, when Svelte 5 was released, I wanted to try something that wasn’t React, and Svelte felt right. As if I were working with HTML, CSS and JavaScript directly. It was simple enough that I could keep going.

$state, in my opinion, is easier to understand from reading the code than just useState.

<script>
let count = $state(0);
</script>
<button onclick={() => count += 1}>{count}</button>
const [count, setCount] = useState(0);
<button onClick={() => setCount(count + 1)}>{count}</button>

I was building a website with a separate third-party API. For me, Svelte felt more familiar, despite working with it less than with React. In React, without libraries, you need to fetch differently, with useEffect.

<script>
import { onMount } from 'svelte';
let data = $state(null);
onMount(async () => {
const res = await fetch(url);
data = await res.json();
});
</script>
const [data, setData] = useState(null);
useEffect(() => {
let ignore = false;
fetch(url)
.then((res) => res.json())
.then((json) => {
if (!ignore) setData(json);
});
return () => {
ignore = true;
};
}, []);

You need to understand how React works in order to understand why it’s done this way.

For example, [] in React means the effect runs only once, after the first render. On every render React compares each item in the array with its previous value, and an empty array has no items to change.

It wasn’t without annoyances. onMount and the $effect rune had similar but still different jobs. The page loaded dynamic data, so my code had to handle the changes. I tried to use $effect instead of onMount, because I thought it was a more modern solution. It worked in most places, but in some places it was broken. I don’t remember what broke, but it was related to auth and the pages people saw after logging in. onMount worked well.

React is still good, especially with the ecosystem around it. Svelte has a smaller community than React, and therefore it has fewer libraries. If there’s some friction in my React code, it’s likely that the community has solved it. In Svelte, if something is made for React, you can’t use it. This meant I had to reinvent the wheel sometimes.

It’s both a downside and an upside. I couldn’t use some libraries, but I relied less on someone else’s code and didn’t increase the app’s bundle with extra libraries.

I tried TanStack Query with Svelte, but found that I didn’t need it. Query added a lot of boilerplate to my code. I removed it and replaced it with $state. But Query was handling caching, and I had to reimplement it. I was working with APIs and many endpoints, so there was a lot of code to rewrite, and the bugs came from replacing Query with my own code.

When I was starting out with both, AI wasn’t as good as it is now. I used it mostly to look things up, not for coding, unless it was boilerplate and something I already knew. It was much easier to look up something for React, given its bigger community. But I liked working with Svelte’s documentation.

I currently don’t have anything made in Svelte. I work with React and TanStack Start. I’d pick React when someone else who uses React will use my thing, say, a component I want to share, or when someone is familiar with React and not Svelte. I’d use Svelte, with SvelteKit, for apps that I want to remain light.

All writing