Having worked recently with Svelte after coming from a React project, I found myself frequently asking “What’s the Svelte way to handle X like I did in React?” The useState hook is probably the most important and most often used hook so I’ve put together a few examples to highlight the differences for anyone who might be peeking over the fence to see if the grass really is greener.
For those of you unfamiliar with Svelte, I recommend you start with the Svelte basics tutorial.
As a refresher, “hooks” in React are functions that allow us to “hook” into the lifecycle of components. The original lifecycle methods like componentDidMount and componentDidUpdate might be familiar to some readers. You can read about the motivation for creating hooks from the React docs. The useState hook gives us a way to create a “state variable,” which allows us to persist state across component re-renders. And maybe more importantly it gives us a way to update that state variable. As such, useState is probably the most common hook you’ll use in a modern React application.
The Svelte Equivalent of React useState
Toggling a boolean value in React
import {useState} from 'react';
export const ToggleValue = () => {
const [bool, setBool] = useState(false);
const toggleBool = () => setBool(!bool);
return (
<>
<div>{bool.toString()}</div>
<button onClick={toggleBool}>Toggle Bool</button>
</>
)
}
The core of this functionality is the useState hook and the toggleBool function. useState returns the “bool” variable we’ll be using and the “setBool” function that we can use to change “bool” when we need to. toggleBool returns the opposite of whatever the current value of “bool” is.
Toggling a boolean value in Svelte
<script>
let bool = false;
const toggleBool = () => bool = !bool;
</script>
<div>Bool: {bool}</div>
<button on:click={toggleBool}>Toggle Bool</button>
In Svelte we see something similar to the above React code with some slight differences. There is a “bool” value and a toggleBool function. What’s missing is something like the “setBool” function returned by useState. In Svelte we have to mutate our component state directly, hence the reassignment that happens in the toggleBool function.
Two other things to note are the difference in the click handler syntax (React’s onClick vs Svelte’s on:click) and how we insert the “bool” value into our html (React needed us to type cast the value to a string vs Svelte allowed us to insert straight).
Manipulating an array in React
import {useState} from 'react';
export const PushPopArray = () => {
const [arr, setArr] = useState([1, 2, 3]);
const pushToArr = () => setArr([...arr, arr.length + 1]);
const popFromArray = () => setArr([...arr.slice(0, -1)])
return (
<>
<button onClick={pushToArr}>Push to Arr</button>
<button onClick={popFromArray}>Pop from Arr</button>
<ul>
{arr.map(el => <li>{el}</li>)}
</ul>
</>
)
}
Similar to the previous example, we use the useState hook to seed our initial state [1, 2, 3] and give us the array variable and its setArr function. Our “push” and “pop” functions follow immutable patterns so we’re not modifying the array directly, we’re making a copy with the data we want to keep. And to display all of the values individually, we’re mapping over the array inside the JSX and returning an html element for each array element.
Manipulating an array in Svelte
<script>
let arr = [1, 2, 3];
const pushToArr = () => arr = [...arr, arr.length + 1];
const popFromArr = () => arr = [...arr.slice(0, -1)];
</script>
<button on:click={pushToArr}>Push to Arr</button>
<button on:click={popFromArr}>Pop from Arr</button>
<ul>
{#each arr as el}
<li>{el}</li>
{/each}
</ul>
In Svelte there are a few differences to note. First, since we ultimately have to mutate our arr variable, we’re using a let and reassigning “arr” inside of our functions. We are still able to use the same pattern for creating the new array, but we have to take that extra step of explicit reassignment instead of using the convenient setArr function. Second, the way you “map” over arrays needs to be done with Svelte’s #each syntax (https://svelte.dev/tutorial/each-blocks). Then within the #each block we can insert our current value into the HTML element we want directly.
Conclusion
It’s easy to implement familiar React patterns in Svelte without too much pain. However, Svelte has its own patterns and syntax for a reason. It doesn’t have a virtual DOM with its render/rerender cycle. While direct comparisons like the above examples are good starting points, for anyone seriously considering Svelte for projects the sooner you embrace the Svelte way of doing things the easier the transition will become.