A 1-On-1 Comparison Between React And Svelte

A 1-On-1 Comparison Between React And Svelte

React currently dominates the codebase of most web applications built using JavaScript. So if you're looking to get into the job market, you're better off learning React.

Svelte, on the other hand, is not yet as popular as React. But it's steadily gaining more and more awareness amongst frontend developers.

In today's article, we'll compare React and Svelte side-by-side by looking at common patterns and design choices by the framework creators.

I'm not here to tell you which one is better; the only way to find that out is by building something with both of them and deciding for yourself.

Sidenote: If you’re new to learning web development, and you’re looking for the best resource to help with that, I strongly recommend HTML to React: The Ultimate Guide.

UI Rendering in React vs Svelte

Both React and Svelte do the same thing: they help developers build reactive UIs with JavaScript by organizing code into reusable components. The syntax is also similar in both frameworks.

React:

<App>
    <HelloWorld/>
<App>

Svelte:

<App>
    <HelloWorld/>
<App>

An end user will not be able to tell the difference between React and Svelte. But when it comes to the developer experience, there's a world of difference between the two frameworks.

React.js uses a runtime called the virtual DOM. Basically, the virtual DOM keeps track of changes made to the application to render these changes in the actual DOM in the browser.

The drawback is that this runtime requires some initial JavaScript, which can be huge in libraries like Next.js. So rendering something like "Hello World" can be quite expensive.

Svelte, on the other hand, takes an entirely different approach; it uses a compiler to eliminate the need for a runtime. The compiler takes your Svelte code and converts it to vanilla JavaScript, which results in a far smaller "Hello World".

State Handling in React vs Svelte

The way you define the state in React is quite different from how you'd do it in Svelte. Let's take a look.

Here we have a basic counter component in React:

import {useState} from "React"

function Counter() {
  const [count, setCount] = useState(0)

  return(
    <button onClick={() => setCount(c => c + 1)}>
        Click me!
    </button>
  )
}

export default Counter

In React, we use functions to create components. Then to add a reactive state, we're to call the useState() hook to get a reactive value and a setter function (for updating the state).

Pretty simple, right?

Well, let's see how it compares to the Svelte side:

<script>
  let count = 0
</script>

<button on:click={() => count++}>
  count is {count}
</button>

In Svelte, you have only one component per file and define the logic within the <script> tags. To create a reactive state, you simply create a variable with the let keyword. From there, you can define a function on the click event, that mutates the value directly.

The Svelte code can be more concise because it doesn't require any imports or function calls to initialize the state.

Props in React vs Svelte

The syntax for passing props is different in React and Svelte. But the way you pass from the parent component is quite similar. Let's see an example.

In React, you pass props to a component by defining them as function arguments, which are typically destructured like so:

function colouredBox({color}) {
  return(
    <p>You picked: {color}</p>
  )
}

With Svelte, things look a lot different. Putting the export keyword in front of a variable allows it to be passed in from the outside:

<script>
  export let color;
</script>

You picked:

Now as I mentioned earlier, using props looks basically identical on frameworks:

// Both React and Svelte
<coloredBox color: {color}/>

However, Svelte does use some syntactic sugar to allow you to easily match variable names with props:

// Only works in Svelte
<coloredBox {color} />

Also, in React, you can pass components as props. But you can't do the same in Svelte:

// React, but not Svelte
return(
  <App header={<CoolHead />} />
)

Passing Children Elements in React vs Svelte

In React it's also possible to pass more than one component from parent to child. To render these "children" elements, you'd use the props.children property:

function Navbar(props){
    return(
      <nav>
        {props.children}
      </nav>
    )
}

This is how you'd pass the children from the parent:

<Navbar>
  <a href="/home">Homepage</a>
  <a href="/about">About Page</a>
</Navbar>

Svelte, on the other hand, uses an entirely different system called <slot />. The default slot is the equivalent of props.children. However, you can also create named slots that'll allow you to insert UI at specific points in this component markup:

<slot name="header" />
</slot >
<slot name="footer" />

NOTE: I have a full-stack web development course that'll teach you how to build an application from scratch. You can get it here.

Creating Lifecycle in React vs Svelte

The syntax for running code when a component is initialized slightly differs in React and Svelte.

In React, we have the useEffect() hook which takes a callback function followed by an empty array. The array signifies that the process doesn't have any dependent data, so it only runs once.

function Navbar() {
  useEffect(() => {
    // run code here
  }, [])
}

In Svelte, we have a similar pattern with the onMount() function:

<script>
  onMount(async() => {
    // handle promise
  })
</script>

The Svelte version is more readable, and more importantly, it can handle an asynchronous function (which is not possible in React).

Creating Side Effect in React vs Svelte

The side effect in React is different from that of Svelte.

With React, we can create a side effect with the useEffect() hook. In the following example, the hook updates the document title any time the count changes:

function Counter() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    document.title = `count is ${count}`
  }, [count])
}

In this case, we tell it to watch count by putting it in the dependencies array.

With Svelte, we have an entirely different mechanism called reactive declarations, which start with a dollar sign and a colon ($:). In the following code, we tell Svelte to rerun the code whenever any dependent data changes.

<script>
  let count;

  $: document.title = `count is ${count}`
</script>

The compiler knows that this code is dependent on the count value, so it updates the document title whenever the value of count changes.

Computed State in React vs Svelte

The code for creating computed state in React is quite different from that of Svelte.

In React, you can easily create computed state by declaring a variable that is dependent on some state. In the following example, the doubled variable is dependent on the count variable (the state):

function Counter() {
  const [count, setCount] = useState(0)

  // computed state
  let doubled = count * 2

  useEffect(() => {
    document.title = `count is ${count}`
  }, [count])
}

The problem is that this code will run every time the component is rendered. This can be a problem if the code contains an expensive computation.

The solution is to wrap the expensive code in useMemo() and explicitly tell it which data it depends on:

function Counter() {
  const [count, setCount] = useState(0)

  // computed state
  let doubled = useMemo(() => count * 2, [count])

  useEffect(() => {
    document.title = `count is ${count}`
  }, [count])
}

This will cache or memorize the value between renders, thereby saving a lot of resources.

In Svelte, the code is much simpler. We can just use the same reactive declaration as before to define a new variable:

<script>
let count;

$: doubled = count * 2
$: document.title = `count is ${count}`
</script>

Again, the compiler automatically knows to only run this code when the count changes.

Creating Conditional Logic in React vs Svelte

React and Svelte both use different templating languages, so the code for creating conditional logic is different in both frameworks.

React uses JSX, a special language that allows you to put HTML in JavaScript. Svelte, on the other hand, has its own templating approach where you bring JavaScript into HTML.

When it comes to conditional logic in React, we can't directly use an if...else statement because the function component needs to return a JavaScript expression that represents a single value.

To represent a true-false situation, we can use a ternary operator:

function Counter() {
  const [count, setCount] = useState(0)

  return(
    {count > 1000 ? <p>big</p> : <p>small</p>}
  )
}

On the other hand, Svelte allows you to create if statements in the HTML, very similar to how you would in normal JavaScript code:

<script>
  let count = 0
</script>

{#if count > 1000}
  <p>Big</p>
{:else}
  <p>Small</p>
{/if}

It's a bit more verbose but also more readable than the ternary operator in React (especially for long conditional chains).

Creating Loops in React vs Svelte

The most common way to loop in React is to use the map() function on an array. This allows you to define a callback function that returns the UI for each item on that array:

function Counter() {
  const items = [
    {id: 1, name: "foo"},
    {id: 2, name: "bar"},
    {id: 3, name: "baz"}
  ]

  return(
    {items.map(() => {
      <div key={item.id}>{item.name}</div>
    })}
  )
}

In Svelte, you can loop over an array of data with an each loop:

<script>
  const items = [
    {id: 1, name: "foo"},
    {id: 2, name: "bar"},
    {id: 3, name: "baz"}
  ]
</script>

{#each items as item (item.id)}
  <p>{item.name}</p>
{/each}

It creates a template variable for each item and then we can use its data inside the tags.

Final thoughts

I hope you learned something new from this article. Furthermore, I would encourage you to get my full-stack web development course if you're looking to build an awesome project from scratch.