Back

All About State Management in Svelte

All About State Management in Svelte

In modern web development, managing application state effectively is not just a best practice but a fundamental necessity that determines how data is shared within the application components. State management is crucial in any interactive application, as it involves tracking and handling its current state data. In this tutorial, you will learn how to manage your Svelte application’s states effectively.

There are numerous benefits to effectively managing your application state, including the following:

  • Improved Performance: Efficient state management can optimize rendering and minimize unnecessary re-renders, thereby enhancing the application’s overall performance.

  • Enhanced Scalability: A well-organized state management approach facilitates the application’s scalability, enabling it to easily handle increasing complexity and user interactions.

  • Maintainability: Effective state management promotes clean and maintainable code by segregating concerns and using a structured approach to handle application data, making it easier to debug and maintain over time.

  • Reusable Components: Through effective state management, components can be designed to be more reusable as they become decoupled from specific data dependencies, allowing for greater flexibility and versatility in application development.

Creating a New Svelte Project

Let’s get started by creating a new Svelte project. To do so, open your terminal, navigate to your working directory, and run the following commands.

npx degit sveltejs/template svelte-project
cd svelte-project
npm install

Using Svelte Props and Context API

In Svelte applications, props and context API can be used to manage state data flow. Let’s explore how we can effectively use props and context API to manage our application states.

Passing State Down to Child Components with Props

Props are values passed from a parent component to a child component. They allow us to pass data down the component tree, enabling parent components to communicate with their children.

Let’s consider, for example, that we want to accept a username as an input in our main component and send the input value to a child component using a prop. To achieve this, create a child component file named ChildComponent.svelte in your project’s src folder and add the following code.

<script>
  export let username;
</script>
<div>
  <h2>Child Component</h2>
  <h3>User Info</h3>
  <p>Username: {username}</p>
</div>

The export statement is used in the code above to access the prop value passed to the current component. We then display the username prop using {username} within the user interface.

Next, in your main component, you can pass the username prop data to the ChildComponent.svelte component by adding the following code to the App.svelte component.

<script>
  import ChildComponent from "./ChildComponent.svelte";
  let username = "";
  function handleChange(event) {
    username = event.target.value;
  }
</script>
<body>
  <div>
    <h1>Parent Component</h1>
    <input
      type="text"
      placeholder="Enter your username"
      on:input="{handleChange}"
    />
    <ChildComponent username="{username}" />
  </div>
</body>
<style>
  body {
    background-color: darkcyan;
  }
</style>

From the code above, we:

  • Import the ChildComponent.svelte component and declare a reactive variable named username, initializing it with an empty string.
  • Define the handleChange() function, which triggers whenever the input field’s value changes, updating the username variable.
  • Create the input field and render the child component.

Now, you should have the child component accessing the username prop, as shown in the GIF image below. oke That’s how you can use props to manage your application data. But what if you want to manage more complex application data? That’s where the Context API comes in.

⁠Using Context API to Share State Across Components

Context API allows us to share application state data between components without having to pass it down through props at every level of the component tree.

With the Context API, we create a context object in a parent component, enabling the sharing of complex application state data. This context can then be accessed in any of its descendant components. This approach provides a more elegant way to manage and share global state or other shared data within our application.

Let’s demonstrate how we can effectively pass user information such as full name, user name, email, and gender from the main component to the child component (ChildComponent.svelte) using Svelte’s built-in Context API. Add the following code to the App.svelte file to do that.

<!-- App.svelte-->
<script>
  import { setContext } from "svelte";
  import ChildComponent from "./ChildComponent.svelte";
  let user = {
    fullName: "Felicia Oke",
    username: "Felicia123",
    email: "Felicia123@gmail.com",
    gender: "Female",
  };
  setContext("userInfo", user);
</script>
<div>
  <h1>Parent Component</h1>
  <ChildComponent />
</div>

From the code above, we:

  • Import the setContext function from Svelte which is used to set the application data globally.
  • Create a user object containing information such as fullname, username, email, and gender.
  • The application state data is shared using the setContext() method, which accepts userInfo as the key name and user as the state object.
  • The <ChildComponent /> template is then used to render the ChildComponent.

Now, let’s access the user state data inside the ChildComponent.svelte file. To do so, open ChildComponent.svelte and replace its code with the following:

<script>
  import { getContext } from "svelte";
  let user = getContext("userInfo");
</script>
<div>
  <h2>Child Component</h2>
  <h3>User Info</h3>
  <p>Fullname: {user.fullName}</p>
  <p>Username: {user.username}</p>
  <p>Email: {user.email}</p>
  <p>Gender: {user.gender}</p>
</div>

In the code above, we import getContext from Svelte to fetch user data from the main component, and then we display the user’s information on the user interface.

Reload the application in your browser. You should have the following output, as shown in the image below: Screenshot 2024-04-04 at 17.22.33

Using Svelte Stores

Svelte stores are a feature in the Svelte framework for managing and sharing reactive state across components in an application. They provide a straightforward way to handle global state and facilitate communication between components without the need for complex state management libraries.

By leveraging Svelte stores, we can achieve efficient and maintainable state management without needing external libraries, prop drilling, or complex state management patterns. This allows us to easily keep track of changes in the application data.

Let’s explore the types of Svelte Stores and how we can effectively use them to manage our application state.

Writable

Writable store in Svelte is a type of store that holds a mutable state. It allows us to store and update data that can be shared across multiple components in our application. Writable stores are particularly useful for managing states that need to be modified from different parts of our application.

Using writable stores involves creating a writable store, updating its value, and subscribing to its component changes. To use writable stores, create a JavaScript file named store.js and add the following code:

import writable from 'svelte/store'
export const WeekDay = writable('sunday')

We can access the store value in any of our application components by adding the following code.

<script>
  import { writable } from "svelte/store";
</script>
<p>The current count is {$WeekDay}</p>

We can update the value of the writable store using its set method, as used in the code below.

WeekDay.set('Friday');

The above code will change the value of WeekDay to Friday from anywhere in our application components.

Readable

A Readable store is a type of store that holds an immutable state. Unlike writable stores, which allow you to update their values, readable stores are read-only. Once initialized, their value cannot be directly modified from outside the store. Below is an example of effectively managing your application state using a Readable store.

Inside the src folder, create a file named store.js and add the following code:

// user.js
import { readable } from 'svelte/store'
export const user = readable({ name: 'John', age: 30 })

To access the Readable store value in the application component, add the following code to the component:

<script>
  import { user } from "./user.js";
</script>
<p>The user's name is {$user.name} and the age is {$user.age}.</p>

Derived

Derived stores enable the creation of reactive data stores computed from existing stores. They’re designed to update automatically based on changes to the base stores they depend on, making them a powerful tool for managing and manipulating data in Svelte applications.

Open the user.js file and add the following code to it:

export const formattedUser = derived(user, ($user) => {
  return {
    fullName: $user.name,
    birthYear: new Date().getFullYear() - $user.age,
  };
});

In this example, formattedUser is a derived store created from the user store. It computes a new value based on the data in the user store. Now, you can use formattedUser in your Svelte components just like any other store. To do that, update the App.svelte code with the following:

<script>
  import { formattedUser } from "./store.js";
  let userInformation;
  formattedUser.subscribe((value) => {
    userInformation = value;
  });
</script>
<div>
  <p>Full Name: {userInformation.fullName}</p>
  <p>Birth Year: {userInformation.birthYear}</p>
</div>

This way, whenever the data in the user store changes, the formattedUser derived store will automatically update its value, and any components subscribed to it will reactively re-render to reflect the changes.

Building a Todo-list with Svelte Store

To put our Svelte Store to practical use, let’s create a todo app and manage the application state using Svelte Store. Follow the steps below to create the todo list.

Create a todos.js file to define the Svelte store for managing todo and add the code below to it:

import { writable } from "svelte/store";
export const todos = writable([
  { id: 1, text: "Learn Svelte state management", completed: false },
  { id: 2, text: "Build a Todo-list with state management", completed: false },
]);

Next, create Svelte components TodoList.svelte, TodoItem.svelte, and AddTodo.svelte to interact with and display the todos.

Inside the TodoList.svelte file, add the following code:

<script>
  import { todos } from "./todos.js";
  import TodoItem from "./TodoItem.svelte";
  $: todoList = $todos;
</script>
<div>
  <h1>Todo List</h1>
  {#each todoList as todo}
  <TodoItem {todo} />
  {/each}
</div>

To mark a todo item as done or not, add the following code to the TodoItem.svelte component:

<script>
  export let todo;
</script>
<div>
  <input type="checkbox" bind:checked="{todo.completed}" />
  <span
    style="
      text-decoration: {
        todo.completed? 'line-through' : &quot;none&quot;;
      }
    "
    >{todo.text}</span>
</div>

To add a new item to the todo list, add the following code to the AddTodo.svelte component:

<script>
  import { todos } from "./todos.js";
  let newTodo = "";
  function addTodo() {
    todos.update((existingTodos) => [
      ...existingTodos,
      { id: Date.now(), text: newTodo, completed: false },
    ]);
    newTodo = "";
  }
</script>
<div>
  <input type="text" bind:value="{newTodo}" placeholder="Enter new todo" />
  <button on:click="{addTodo}">Add</button>
</div>

Now, to connect all the todo list components together, replace the code in App.svelte with the following:

<script>
  import TodoList from "./TodoList.svelte";
  import AddTodo from "./AddTodo.svelte";
</script>
<body>
  <main>
    <TodoList />
    <AddTodo />
  </main>
</body>

<style>
  body {
    background-color: darkcyan;
  }
  main {
    padding: 20px;
    margin-left: 30%;
  }
</style>

Save your code and open http://localhost:8080/ in your browser. You should see the output in the GIF image below. todo

Conclusion

State management plays a crucial role in application development, enabling the tracking of data changes and effective management of the application state. In Svelte, a lightweight framework, numerous techniques can be employed to manage the state efficiently.

In this tutorial, we explored various approaches to managing the Svelte application state and demonstrated how to effectively manage a todo app’s state to improve application performance and maintenance.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay