So you can see that we have passed the same data into both, but the structure is a bit different.

With React — or at least since 2019 — we would typically handle state through a series of Hooks. These might look a bit strange at first if you haven’t seen this type of concept before. Basically, it works as follows:

Let’s say we want to create a list of todos. We would likely need to create a variable called list and it would likely take an array of either strings or maybe objects (if say we want to give each todo string an ID and maybe some other things. We would set this up by writing const [list, setList] = useState([]) . Here we are using what React calls a Hook — called useState. This basically lets us keep local state within our components.

Also, you may have noticed that we passed in an empty array [] inside of useState() . What we put inside there is what we want list to initially be set to, which in our case, we want to be an empty array. However, you will see from the image above that we passed in some data inside of the array, which ends up being the initialised data for list . Wondering what setList does? There will be more on this later!

Now with Svelte, you will notice that we have two variables that we are exporting. These were located inside of our ToDo.svelte file, but can be placed higher up inside of our route App.svelte file if we wanted to.

Anyway, let’s just take another look at them, then we’ll explain what is going on:

export let todo = "";

export let list = [

{ id: 1, text: "clean the house" },

{ id: 2, text: "buy eggs" }

];

So with Svelte, if we want to refer to things such as todo and list in our file, we need to have created a reference to them somewhere in the same file.

This is no different to React, or most other JavaScript, whether it be through creating a variable, importing a variable, or passing a variable down to a component as props. The different here is that we’re effectively creating new variables (with let , not const as that would prevent us from being able to mutate it — or reassign it if we want to get technical about how const works). The reason why I mention that we have to create new variables is because you’ll later notice that we have to do this in every file that we want to refer to them, even if they’ve already been passed down as props. Basically what happens is that Svelte will then pass the values down to those newly created variables. If you’re confused, just continue reading on and you’ll see how this works when we refer to it again later.

So how do we reference our mutable data in our Svelte app?

Well, let’s say that we have some piece of data called name that has been assigned a value of ‘Sunil’ .

In Svelte, this let name = Sunil , will have either been created in a component and passed down to another as a prop, or just gets used inside of the component it was created in. Regardless of how we use name , we can update it by simply reassigning name . So I could write name = ‘John' and we would see the update in our screen in the UI. I’m not sure how I feel about being called John, but hey ho, things happen! 😅

In React, as we have our smaller pieces of state that we created with useState() , it is likely that we would have created something along the lines of const [name, setName] = useState('Sunil') . In our app, we would reference the same piece of data by calling simply calling name . Now the key difference here is that we cannot simply write name = ‘John’ , because React has restrictions in place to prevent this kind of easy, care-free mutation-making. So in React, we would write setName('John') . This is where the setName bit comes into play. Basically, in const [name, setName] = useState('Sunil') , it creates two variables, one which becomes const name = 'Sunil' , while the second const setName is assigned a function that enables name to be recreated with a new value.

Effectively React and Svelte are doing the same thing here, which is creating data that can be updated. Svelte essentially combines its own version of name and setName by default whenever a piece of data gets updated. So in short, React requires that you call setName() with the value inside in order to update state, Svelte makes an assumption that you’d want to do this if you were ever trying to update values that appear in the DOM (ie. values that we can see on the screen in our browser). So Why does React even bother with separating the value from the function, and why is useState() even needed? It’s because this signifies to React wants it needs to re-render whenever state changes. It would know that the state has changed because the useState function was called.

Bean knew best.

Now that we have mutations out of the way, let’s get into the nitty, gritty by looking at how we would go about adding new items to both of our To Do Apps.

How do we create new To Do Items?

React:

const createNewToDoItem = () => { const newId = list.length ?

Math.max.apply(null, list.map(t => t.id)) + 1 :

1; const newToDo = { id: newId, text: toDo };

setList([...list, newToDo]);

setToDo(""); };

How did React do that?

In React, our input field has an attribute on it called value. This value gets automatically updated every time its value changes through what is known as an onChange event listener. The JSX (which is basically a variant of HTML), looks like this:

<input type="text"

value={toDo}

onChange={handleInput}/>

So every time the value is changed, it updates state. The handleInput function looks like this:

const handleInput = (e) => {

setToDo(e.target.value);

};

Now, whenever a user presses the + button on the page to add a new item, the createNewToDoItem function is triggered. Let’s take a look at that function again to break down what is going on:

const createNewToDoItem = () => { const newId = list.length ?

Math.max.apply(null, list.map(t => t.id)) + 1 :

1; const newToDo = { id: newId, text: toDo };

setList([...list, newToDo]);

setToDo(""); };

Essentially the newId function is basically creating a new ID that we will give to our new toDo item. The newToDo variable is an object that takes that has an id key that is given the value from newId . It also has a text key which takes the value from toDo as its value. That is the same toDo that was being updated whenever the input value changed.

We then run out setList function and we pass in an array that includes our entire list as well as the newly created newToDo .

If the ...list , bit seems strange, the three dots at the beginning is something known as a spread operator, which basically passes in all of the values from the list but as separate items, rather than simply passing in an entire array of items as an array. Confused? If so, I highly recommend reading up on spread because it’s great!

Anyway, finally we run setToDo() and pass in an empty string. This is so that our input value is empty, ready for new toDos to be typed in.

Svelte:

createNewToDoItem() { const newId = list.length ?

Math.max.apply(null, list.map(t => t.id)) + 1 :

1;



list.push({ id: newId, text: todo });

todo = ""; }

How did Svelte do that?

In Svelte, our input field has a handle on it called bind:value. This allows us to do something known as two-way binding. Let’s just quickly look at our input field, then we’ll explain what is going on:

<input type="text" bind:value={todo} />

bind:value ties the input of this field to a variable we have called todo . When the page loads, we have todo set to an empty string, as such: let todo = ‘’ . If this had some data already in there, such as let todo = ‘add some text here’ , our input field would load with add some text here already inside the input field. Anyway, going back to having it as an empty string, whatever text we type inside the input field gets bound to the value for todo . This is effectively two-way binding (the input field can update todo and todo can update the input field).

So looking back at the createNewToDoItem() code block from earlier, we see that we push the contents of todo into the list array and then update todo to an empty string.

We also used the same newId() function as used in the React example.

How do we delete from the list?

React:

const deleteItem = (item) => {

setList(list.filter((todo) => todo.id !== id));

};

How did React do that?

So whilst the deleteItem() function is located inside ToDo.js, I was very easily able to make reference to it inside ToDoItem.js by firstly, passing the deleteItem() function as a prop on <ToDoItem/> as such:

<ToDoItem deleteItem={deleteItem}/>

This firstly passes the function down to make it accessible to the child. Then, inside the ToDoItem component, we do the following:

<button className="ToDoItem-Delete"

onClick={() => deleteItem(item.id)}> - </button>

All I had to do to reference a function that sat inside the parent component was to reference props.deleteItem. Now you may have noticed that in the code example, we just wrote deleteItem instead of props.deleteItem . This is because we used a technique known as destructuring which allows us to take parts of the props object and assign them to variables. So in our ToDoItem.js file, we have the following:

const ToDoItem = (props) => {

const { item, deleteItem } = props;

}

This created two variables for us, one called item , which gets assigned the same value as props.item , and deleteItem , which gets assigned the value from props.deleteItem . We could have avoided this whole destructuring thing by simply using props.item and props.deleteItem , but I thought it was worth mentioning!

Svelte:

const deleteItem = id => {

list = list.filter(item => item.id !== id);

};

How did Svelte do that?

Quite a similar approach is deployed here in Svelte. In our ToDo.svelte file, we pass our deleteItem function down to <ToDoItem/> as such:

<ToDoItem {item} deleteItem={deleteItem}/>

Then in our ToDoItem.svelte file, we create a variable reference at the top of our file by writing export let deleteItem; . This allows us to make references to deleteItem as normal. Then finally, we pass our function to our ‘delete’ button inside of ToDoItem.svelte, like so:

<button class=”ToDoItem-Delete”

on:click={() => deleteItem(item.id)}> - </button>

As you can see, our ‘delete’ button is exactly the same as the one we used in React.

How do we pass DOM event listeners?

React:

Event listeners for simple things such as click events are straight forward. Here is an example of how we created a click event for a button that creates a new ToDo item:

<button className=”ToDo-Add” onClick={createNewToDoItem}>+</button>.

Super easy here and pretty much looks like how we would handle an onclick with regular JavaScript.

Svelte:

In Svelte it is also pretty straight-forward. We simply use the on: handle, and then the type of event-listener we want to do. So for example, to add a click event listener, we could write on:click, as we have in the following example:

<button class="ToDo-Add" on:click={createNewToDoItem}>+</button>

One cool thing with Svelte event listeners is that there are also a bunch of things that you can chain on to them, such as once which prevents the event listener from being triggered more than once.

How do we pass data/props to a child component?

React:

In react, we pass props onto the child component at the point where it is created. Such as:

<ToDoItem key={key.id} item={todo} />

Here we see two props passed to the ToDoItem component. From this point on, we can now reference them in the child component via this.props. So to access the item.todo prop, we simply call props.item.

Svelte:

In Svelte, it’s pretty much the same:

<ToDoItem {item} on:deleteItem={deleteItem} />

One difference here is that we didn’t have to pass a key to our ToDoItem, but hold that thought for a moment as we’ll cover that later.

Another difference is that we can pass item down by simply writing {item} . This is because the prop name and the actual prop have the same name. Writing item={item} would also work the same, but my Svelte setup automatically amended it to simply {item} .

Once this is done, we have to create a variable inside of our ToDoItem.svelte file called item , by writing export let item; towards the top of the <script> part of the file. This is so that we can refer to item in our file without getting any errors for trying to reference a variable that doesn’t exist. What you have to remember here is that during compilation, Svelte will then check to see if our ToDoItem was passed a prop with the name of item . In our case, it has, so the value of item that was passed down as a prop, will be assigned to our export let item; . This then allows our app to work as we would expect it to. These can then be referenced in the child by their name — so in our case, ‘todo’.

How do we emit data back to a parent component?

React:

We firstly pass the function down to the child component by referencing it as a prop in the place where we call the child component. We then add the call to function on the child by whatever means, such as an onClick, by referencing props.whateverTheFunctionIsCalled — or whateverTheFunctionIsCalled if we have used destructuring. This will then trigger the function that sits in the parent component. We can see an example of this entire process in the section ‘How do we delete from the list’.

Svelte:

This is handled in a very similar way to how it is in React. We can see an example of this entire process in the section ‘How do we delete from the list’.

How do we loop through data inside of our components?

React

In React we typically use higher order functions such as map() , filter() etc to loop through data to either pass the data through to html elements or to child components. This is how we implemented it in our code:

{list.map((item) => {

return <ToDoItem key={item.id}

item={item}

deleteItem={deleteItem} />;

})}

This feels very similar to how we might use them in regular JavaScript.

Svelte

In Svelte, we use #each , which is specific to Svelte. It is a means by which to loop through data. This is how we implemented it in our code:

{#each list as item, i (item.id)}

<ToDoItem {item} on:deleteItem={deleteItem} />

{/each}

You’ll notice that we then take our list variable and follow it with as item . This is basically saying, take our list , and break it down to individual items which we will refer to as item . We then give each item an index which we call i and then write in brackets immediately after what we want to use as the index, which in this case, is our item.id . You will also notice that we did not have to pass a key to our <ToDoItem/> here as Svelte assigns it anyway.

And there we have it! 🎉

We’ve looked at how we add, remove and change data, pass data in the form of props from parent to child, and send data from the child to the parent in the form of event listeners. There are, of course, lots of other little differences and quirks between React and Svelte, but hopefully the contents of this article has helped to serve as a bit of a foundation for understanding how they both handle stuff.

If you’re interested in forking the styles used in this article and want to make your own equivalent piece, please feel free to do so! 👍

Github links to both apps:

React ToDo: https://github.com/sunil-sandhu/react-todo-2019

Svelte ToDo: https://github.com/sunil-sandhu/svelte-todo

What about comparing Svelte with Vue?

I’m glad you asked! Here’s the link below:

https://medium.com/@sunilsandhu/i-created-the-exact-same-app-in-vue-and-svelte-here-are-the-differences-c649f8d4ce0a