Introducing State Management with Runes
Introducing State Management with Runes
Welcome to the second course in our "Building A Kanban Board" series! In our previous course, we built the foundational UI components for our Kanban board: the main layout, columns, and task cards.
Now it’s time to make our board fully functional by connecting it to dynamic data using Svelte's Runes API.
Bridging from UI to State
While our components from the previous course look great, they're currently displaying static, hardcoded tasks. In a real Kanban application, we need:
- A central place to store all our tasks
- A way to filter tasks by status (To Do, In Progress, Done)
- The ability to move tasks between columns
- A reactive system that updates the UI when tasks change
That’s where state management comes in — and Svelte’s Runes provide an elegant solution.
What is State Management
State management is a fundamental concept in modern web applications. It refers to how we organize, store, and update data that changes over time in our application. For our Kanban board, we'll need to manage tasks that can move between different columns (To Do, In Progress, and Done), and we'll need our UI to update automatically when this data changes.
Svelte 5 introduces a new way to handle reactivity called Runes. Runes are special functions prefixed with a dollar sign ($) that enhance variables with special behaviors. They replace the older reactive syntax in previous Svelte versions and provide a more intuitive way to work with reactive state.
In this lesson, we'll focus on creating a task store that will serve as the central data repository for our Kanban board application. This store will:
- Hold our collection of tasks.
- Provide filtered lists of tasks for each column.
- Expose functions to access these lists from our components.
- Connect this accessor functions to our board component
Let's get started by exploring how to create reactive state with Svelte 5's Runes!
Creating Reactive State with `$state`
The first step in building our task store is to create a reactive state variable that will hold our collection of tasks. For that we use the $state rune to make a reactive variable.
Here's how we'll create our initial tasks array:
Let's break down what's happening here:
- We're creating a file called
taskStore.svelte.jsin thesrc/libdirectory. - We're using the
$staterune to make ourtasksarray reactive. - We're initializing it with four sample tasks.
- Each task has an
id,title,description, andstatusproperty. - The
statusproperty determines which column the task belongs to.
When we use $state, Svelte automatically tracks any changes to this variable. If we add, remove, or modify tasks in this array, any components that depend on this data will automatically update.
For example, if we were to add a new task:
Svelte would detect this change and update any UI elements that display our tasks. This is the power of reactivity in Svelte — we don't need to manually trigger UI updates when our data changes.
Filtering Tasks with `$derived`
Now that we have our tasks array, we need a way to filter tasks based on their status. This will allow us to display the right tasks in each column of our Kanban board.
In Svelte, we can use the $derived rune to create values that are computed from other reactive values. When the source values change, the derived values are automatically recalculated.
Let's add filtered task lists for each column:
Here, we're creating three derived values:
todoTasks: Contains all tasks with a status of 'todo'.inProgressTasks: Contains all tasks with a status of 'inprogress'.doneTasks: Contains all tasks with a status of 'done'.
These derived values will automatically update whenever the tasks array changes. For example, if we move a task from 'todo' to 'inprogress' by changing its status, the todoTasks and inProgressTasks arrays will automatically update to reflect this change.
The beauty of using $derived is that we don't need to manually recalculate these filtered lists. Svelte handles this for us, ensuring our UI always shows the most up-to-date data.
Exporting State and Accessor Functions
The final step in building our task store is to export functions that allow other parts of our application to access our filtered task lists.
In Svelte, we can't export $derived values directly. There are several important reasons for this limitation:
-
Reactivity Boundaries: Svelte's reactivity system is designed to work within component boundaries. When you export a derived value directly, it can break the reactivity chain as it crosses these boundaries.
-
Referential Stability: Direct exports might create new object references when used outside their original context, potentially causing unnecessary re-renders.
-
Implementation Details: The Runes API uses internal mechanisms to track dependencies between reactive values. Exporting these values directly could expose internal implementation details that might change in future versions.
-
Encapsulation: By using accessor functions, we create a cleaner API that hides the implementation details of our state management. This allows us to change how we store and derive our data without affecting the code that uses it.
Instead, we use accessor functions that return these values:
These functions simply return our filtered task lists. Components can call these functions to get the tasks they need to display.
For example, a component that displays the "To Do" column might use getTodoTasks() to get the list of tasks it needs to render.
Updating the Board Component to Use Dynamic Data
Now let’s connect the Board component to the task store. Since the Column and TaskCard components are already set up, we only need to replace the hardcoded tasks in the Board component with dynamic data.
Here’s the updated Board.svelte:
State Management Best Practices
- Local Component State: Use local
$statevariables within a component when the state is only relevant to that single component. - Shared Store State: Use a dedicated store module when multiple components need access to the same data.
- Atomic Updates: Keep state update functions focused on a single task.
- Validation: Add validation in your state management functions to ensure data integrity.
- Error Handling: Validate inputs and provide clear errors when adding or modifying tasks.
- Performance Considerations: Minimize unnecessary component re-renders and batch updates when possible.
Summary and Next Steps
In this lesson, we've learned how to create a task store using Svelte's Runes API. Let's recap what we've covered:
- We used the
$staterune to create a reactive tasks array that will automatically trigger UI updates when modified. - We used the
$derivedrune to create filtered task lists for each column of our Kanban board. - Connected the
Boardcomponent to display dynamic tasks using accessor functions.
This task store will serve as the foundation for our Kanban board application. In the upcoming lessons, we'll build on this foundation by:
- Creating the state to the components to display our tasks dynamically.
- Adding a form to create new tasks.
- Implementing functionality to move tasks between columns.
In the practice exercises that follow, you'll get hands-on experience working with Svelte 5's Runes. You'll create your own reactive state, derive values from that state, and build functions to modify your state. These exercises will help reinforce the concepts we've covered in this lesson and prepare you for the more complex state management patterns we'll explore in future lessons.
Remember, the key to mastering state management is practice. Don't worry if these concepts feel new or challenging at first — as you work through the exercises and build more of the application, they'll become more familiar and intuitive.
