Easily restore your project to a previous version with our new Instant One-click Backup Recovery

Svelte vs. React: Which should you choose for your project?

We'll discuss each framework's core concepts, explore its key features and use cases, and help you decide which one is best for your next project.
Asaolu Elijah

Asaolu Elijah

Apr 09, 2024
Svelte vs. React

React and Svelte are two JavaScript frameworks that have revolutionized how we build web applications. Both offer powerful tools for creating dynamic and interactive UIs, but they take fundamentally different approaches.

In this article, we'll break down each framework's core concepts, explore its key features and use cases, and help you decide which one might be the best fit for your next project. We'll also build an app that fetches GraphQL data in both frameworks to explore their developer experience further.

#What is Svelte?

Svelte is a robust open-source JavaScript framework designed for building user interfaces. It was created by Rich Harris and officially released in November 2016. Svelte was designed to take a unique approach compared to traditional frameworks by moving a significant portion of the work to compile time; this results in several key advantages, including exceptional performance, smaller bundle sizes, and even simplified development, as you don't need to write complex logic to manage virtual DOM updates.

Svelte's operation can be broken down into several key areas that distinguish it from other frameworks.

  • Compile-time optimization: Svelte pre-renders UI components during compilation, resulting in smaller bundle sizes and faster load times. This eliminates the need for a virtual DOM at runtime.

  • Reactive updates: Svelte employs a unique reactivity system where any variable in the component becomes reactive by default. Changes trigger efficient DOM updates, simplifying state management.

  • Zero runtime overhead: Svelte has a minimal runtime footprint, unlike other frameworks. The compiled code is lean, focusing solely on the application logic and leading to superior performance.

Creating a new Svelte application is pretty straightforward. With Node.js installed, you can set up a basic project by running the command below.

npx degit sveltejs/template <project-name>
cd <project-name> && npm install

Running this command will scaffold a new svelte project and display a command to start your application once it is completed.

Svelte components

A typical Svelte component uses a concise and intuitive syntax, blending HTML, JavaScript, and CSS in a single file. Here's an example:

<script>
let count = 0;
function increment() {
count++;
}
</script>
<h1>The count is: {count}</h1>
<button on:click={increment}>Increment</button>

In this example, the <script> tag contains the component's reactive state and logic, while the HTML-like syntax outside the <script> tag defines the UI. The {count} syntax is used for data binding, automatically updating the DOM when the count variable changes. The {count} tag scopes styles to the component, preventing unintended side effects.

State management in Svelte

Svelte embraces a reactive programming paradigm where variables declared within your component become automatically reactive; we saw this in the previous code example.

For more complex scenarios, Svelte offers writable stores. Stores are special objects that can hold state in a way that is accessible across multiple components. Here's a brief example:

<script>
import { writable } from 'svelte/store';
const count = writable(0);
function increment() {
count.update(n => n + 1);
}
</script>
<h1>The count is: {$count}</h1>
<button on:click={increment}>Increment</button>

In this code example, the count becomes a writable store. The $ symbol is used to automatically subscribe to store changes, making the syntax for using stores as reactive variables incredibly simple.

Handling events in Svelte

Event handling in Svelte is seamlessly integrated into the component markup. As shown in the previous example, listening for a button click is as simple as adding the on:click directive to the button element. Svelte supports a wide range of standard DOM events, and the syntax for listening to them follows this consistent pattern.

Beyond handling native DOM events, Svelte components can dispatch custom events, enabling complex interaction patterns between nested components.

<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
function sayHello() {
dispatch('hello', { message: 'Hello world!' });
}
</script>
<button on:click={sayHello}>Say Hello</button>

In this example, the sayHello() function dispatches a hello event with an accompanying message. Parent components can listen for this event using the on:hello directive, enabling them to react accordingly.

#What is React?

React is a declarative, efficient, and flexible JavaScript library for building user interfaces. It was developed by Facebook and first released in 2013. React stands out for its virtual DOM feature that optimizes rendering and improves app performance, making it one of the most popular libraries for web development. Its component-based architecture enables developers to build large-scale applications with data that changes over time in an easy and maintainable way.

React's core functionalities can be broken down into the following concepts:

  • Declarative & component-based: React uses a declarative approach where you define UI for each state. Components manage their state and logic, promoting code reusability and separation of concerns. This separation also keeps the state from the DOM and allows easy data flow through the application.

  • Virtual DOM: React employs a virtual DOM, a lightweight copy of the real DOM. When the state changes, React updates the virtual DOM and efficiently calculates the minimal changes needed for the real DOM, resulting in performant UI updates.

Setting up a new React project is straightforward, especially with the Vite tooling system.

npx create-vite@latest my-react-app --template react
cd my-react-app && npm install
npm run dev

This will create a new React project, install dependencies, and launch a development server to test your application.

Let's examine a typical React component, Hello, which accepts a prop message and renders it within a paragraph element:

function Hello({ message }) {
return (
<div>
<h1>Hello!</h1>
<p>{message}</p>
</div>
);
}
export default Hello;

In this example, Hello is a functional component demonstrating the React component structure's essentials. The component receives props - in this case, {message} - as an argument. This prop is used within JSX to dynamically render the value of message passed to the Hello component.

JSX

JSX is the core of React component development. It resembles HTML in appearance but is syntactic sugar for React.createElement() calls allow developers to write components in a familiar and easy-to-understand syntax.

For instance, our Hello component above utilizes basic JSX to define the UI. JSX allows for the dynamic inclusion of JavaScript values and expressions using curly braces {}, which enables the rendering of dynamic data, as seen with {message}.

JSX contributes significantly to React's ability to build robust applications as it enhances the component code's expressiveness and facilitates the declaration of structures seamlessly combining HTML and JavaScript logic.

State Management in React

React employs the useState hook for basic state management within functional components. This hook lets you add React state to function components, making them "stateful." Here's a basic example:

import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

In this Counter component, useState is used to create a count state variable. The setCount function is used to update the value of count. React re-renders the component with the updated state whenever setCount is called.

Beyond useState, React offers more hooks for managing complex state logic, including useEffect for side effects, useContext for managing global state, and useReducer for more complex state logic, among others.

Handling Events in React

Event handling in React is achieved through JSX attributes that resemble the native HTML event attributes but are written in camelCase. Here's how you can handle events in React:

import React from 'react';
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}

In the ActionLink component, the onClick attribute is used to attach a click event listener to the anchor tag. Then the handleClick function is executed whenever the link is clicked.

#Key differences between Svelte and React

Now that we've covered the basics of both frameworks, including how they work behind the scenes and their features, here's a table outlining their major differences.

FeatureSvelteReact
CompilationCompile-time to optimized JS.Runtime library interpreting JSX.
DOM UpdatesDirect, without virtual DOM.Uses virtual DOM for diffing updates.
State ManagementReactive variables & stores.useState, useReducer, context.
SyntaxSimilar to HTML/CSS/JS, less boilerplate.JSX, requires transpilation.
ReactivityAutomatic on variable changes.Manually triggered via hooks.
Bundle SizeSmaller initial size due to compilation optimizations.Larger, depending on library size and usage.
EcosystemGrowing, with essential tools integrated (e.g., SvelteKit).Extensive, with many third-party libraries.
Learning CurveConsidered lower due to simplicity and less boilerplate.Steeper due to JSX and hooks concepts.

#Similarities between Svelte and React

Despite their different approaches, Svelte and React share core concepts that make them both powerful UI tools:

  • Component-Based Architecture: Both frameworks utilize components for code reusability, maintainability, and a clear separation of concerns.

  • Declarative UI: With both frameworks, you can define your desired UI state, and the frameworks handle efficient updates. This simplifies development and debugging.

  • Data Binding: Both offer ways to link component state and UI, ensuring the UI automatically reflects the latest state.

  • Event Handling: Both provide ways to handle user interactions through event listeners, allowing you to react to user input and update your application state.

#Use cases for Svelte and React

When choosing between Svelte and React for a project, it's essential to consider the project's specific requirements and goals due to each framework's distinct advantages.

Svelte shines in scenarios where performance and speed are paramount, such as in single-page applications (SPAs) and progressive web apps (PWAs). Its compile-time optimization leads to faster initial load times and efficient updates, making it ideal for creating responsive, high-performance web applications. Additionally, Svelte's minimalistic approach and smaller bundle sizes are particularly advantageous for developing embedded widgets or components seamlessly integrated into various environments without heavy dependencies.

On the other hand, React is highly favored for its robustness and versatility in building complex, large-scale applications. A vast array of libraries and tools backs its ecosystem. The React Native framework also extends this capability to mobile app development, allowing for the creation of cross-platform mobile applications with a single JavaScript codebase. React's virtual DOM ensures efficient rendering, making it suitable for dynamic web applications that require frequent data updates. Furthermore, React's popularity and extensive community support make it a reliable option for enterprise-level applications, where long-term maintenance and scalability are critical considerations.

#Fetching GraphQL data in React vs. Svelte

Both frameworks offer robust methods for integrating GraphQL queries into your applications, albeit through slightly different approaches. Let’s explore how this works.

To fetch GraphQL data, you’ll need access to a GraphQL endpoint. You can easily create one from your Hygraph dashboard, configure the content structure to your choice, and easily retrieve your content API endpoints. However, for the sake of this tutorial, I've created one using the Hygraphlix template, with the following URL as the public GraphQL endpoint:

https://api-us-east-1-shared-usea1-02.hygraph.com/v2/cluh3nib3000008jk3ippd87t/master

With this, we can send GraphQL queries to this endpoint and retrieve movie data.

Fetching GraphQL data in React

To proceed, run the following command to create a new React application:

npx create-vite@latest react-hygraph --template react

Next, change into the app directory and install all necessary dependencies with the following command.

cd react-hygraph
npm install

To request GraphQL endpoints, we’ll need to install a GraphQL client. To continue, execute the command below.

npm install @apollo/client graphql

Running this command adds Apollo Client and GraphQL to your project. The Apollo Client allows you to manage local and remote data with GraphQL.

Next, open the default src/main.jsx file in your React project directory and replace its content with the following code.

import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { ApolloClient, InMemoryCache, ApolloProvider } from "@apollo/client";
const client = new ApolloClient({
uri: "https://api-us-east-1-shared-usea1-02.hygraph.com/v2/cluh3nib3000008jk3ippd87t/master",
cache: new InMemoryCache(),
});
ReactDOM.createRoot(document.getElementById("root")).render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>
);

Here, we are importing the ApolloClient, InMemoryCache, and ApolloProvider from @apollo/client. We then initialize ApolloClient with our GraphQL API endpoint and wrap our application's component tree with ApolloProvider.

To add some aesthetic to our application, open src/App.css and paste the following code.

#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.movies-container {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.movie-card {
border: 1px solid #ccc;
padding: 20px;
border-radius: 8px;
}
img {
width: 100%;
max-height: 300px;
object-fit: cover;
border-radius: 4px;
}

Next, open src/App.jsx and replace its content with the code below.

import { useQuery, gql } from "@apollo/client";
import "./App.css";
const GET_MOVIES = gql`
query Movies {
movies(first: 10) {
id
federateMovie {
data {
Title
Poster
Genre
Director
}
}
}
}
`;
function App() {
const { loading, error, data } = useQuery(GET_MOVIES);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return (
<div className="movies-container">
{data.movies.map(({ federateMovie: { data: movieData }, id }) => (
<div key={id} className="movie-card">
<h3>{movieData.Title}</h3>
<img src={movieData.Poster} alt={movieData.Title} />
<p>Genre: {movieData.Genre}</p>
<p>Director: {movieData.Director}</p>
</div>
))}
</div>
);
}
export default App;

In this updated code, we leveraged Apollo’s gql tag to define our query. We also used the useQuery hook to execute the query and access the loading, error, and data states. Finally, we looped through the data in our markup and rendered a movie card for each iteration.

Start your application by running the following command.

npm run dev

The movie data from our Hygraph GraphQL API should now be displayed in our browser, as shown in the image below.

Let’s recreate our movie app with Svelte to compare their developer experience!

Fetching GraphQL data in Svelte

Start by creating a new Svelte application by running the command below.

npx degit sveltejs/template svelte-hygraph

Change into your new app directory and install its default dependencies.

cd svelte-hygraph && npm install

Next, install GraphQL and the svelte-apollo client.

npm install svelte-apollo @apollo/client graphql

To proceed, create a new Movie.svelte component inside the default src/ directory and paste the following code into it.

<script>
import { query } from "svelte-apollo";
import { gql } from "@apollo/client/core";
const GET_MOVIES = gql`
query Movies {
movies(first: 10) {
federateMovie {
data {
Title
Poster
Genre
Director
}
}
id
slug
}
}
`;
const movies = query(GET_MOVIES);
</script>
<div class="movies-container">
{#if $movies.loading}
Loading...
{:else if $movies.error}
Error: {$movies.error.message}
{:else}
{#each $movies.data.movies as { federateMovie: { data: movie }, id }}
<div key={id} class="movie-card">
<h3>{movie.Title}</h3>
<img src={movie.Poster} alt={movie.Title} />
<p>Genre: {movie.Genre}</p>
<p>Director: {movie.Director}</p>
</div>
{/each}
{/if}
</div>
<style>
.movies-container {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.movie-card {
border: 1px solid #ccc;
padding: 20px;
border-radius: 8px;
}
img {
width: 100%;
max-height: 300px;
object-fit: cover;
border-radius: 4px;
}
</style>

In the code above, we create a new component to render our movies; this component defines the GraphQL query, fetches the data from our endpoint, and iterates through each movie data to render a card.

However, we're not done just yet; we also need to configure our graph client. Open src/App.svelte and replace its content with the following code.

<script>
import { ApolloClient, InMemoryCache } from "@apollo/client/core";
import { setClient } from "svelte-apollo";
import Movies from "./Movies.svelte";
const client = new ApolloClient({
uri: "https://api-us-east-1-shared-usea1-02.hygraph.com/v2/cluh3nib3000008jk3ippd87t/master",
cache: new InMemoryCache(),
});
setClient(client);
</script>
<Movies />

Here, we set up a GraphQL client, defined our endpoint, and imported the Movies component we created earlier.

Start your application by running the following command.

npm run dev

You should now see the movie card displayed in your browser, similar to React’s example!

In evaluating the developer experience between React and Svelte from this basic app, notable distinctions emerge in syntax, state management, and component styling.

React uses JSX, which mixes HTML with JavaScript. Many developers are used to this and make things like looping through data with .map() natural to those accustomed to JS array operations. On the other hand, Svelte's way of doing things, such as looping with {#each ...} and conditionals ({#if ...}), might require a slight learning curve to grasp fully.

Svelte makes styling easy by letting you write CSS directly in your components. It keeps styles specific to each component without extra work. React often needs extra tools like styled components to do this, which means more steps and more code. Understanding these differences is crucial in deciding which framework best fits your needs.

#Conclusion

In this tutorial, we explored the key differences between React and Svelte. We delved into their contrasting syntax, state management, and event-handling approaches. Additionally, we showcased how each framework tackles GraphQL data fetching, highlighting their unique developer experience.

If you're interested in diving deeper, explore the React app example and the Svelte example here.

Blog Author

Asaolu Elijah

Asaolu Elijah

Asaolu Elijah is an experienced software engineer and technical writer. He is passionate about sharing his knowledge and helping others achieve their goals in the tech industry. In his free time, Elijah enjoys gaming and exploring new technologies.

Share with others

Sign up for our newsletter!

Be the first to know about releases and industry news and insights.