/

Cross-component State Management in Svelte: How to Pass State Between Components

Cross-component State Management in Svelte: How to Pass State Between Components

In Svelte, handling the state of a single component is straightforward. However, what about passing state between components? In this blog post, we’ll explore different techniques for cross-component state management in Svelte using props, the Context API, and Svelte stores.

Passing State Using Props

The common strategy in many UI frameworks is to pass state between components using props, also known as “lifting the state up.” When a component needs to share data with another, the state can be moved up in the component tree until there’s a common parent for those components. The state is then passed down from the parent component to the child components using props. This technique is simple and effective for managing state.

For more information on props in Svelte, check out the Svelte Props tutorial.

The Context API

There are scenarios where using props is not practical. For example, when two components are so distant in the component tree that moving the state up to the top-level component becomes cumbersome. In such cases, the Context API can be used to let multiple components communicate with their descendants without passing props around.

The Context API provided by the svelte package includes two functions: setContext and getContext. To set an object in the context and associate it with a key, use the setContext function:

1
2
3
4
5
import { setContext } from 'svelte';

const someObject = {};

setContext('someKey', someObject);

To retrieve the object assigned to a key in another component, use the getContext function:

1
2
3
import { getContext } from 'svelte';

const someObject = getContext('someKey');

Note that you can only use getContext in the component that used setContext or its descendants.

Using Svelte Stores

Svelte stores are an excellent tool for handling cross-component state management without excessive prop passing. To use Svelte stores, import the writable function from svelte/store:

1
import { writable } from 'svelte/store';

Then, create a store variable using the writable() function and pass the default value as the first argument:

1
const username = writable('Guest');

You can put the store in a separate file, such as store.js, and import it into multiple components:

1
import { username } from './store.js';

To set the value of the store variable, use the set() method and pass the new value as the first argument:

1
username.set('new username');

To update the value of the store variable using the update() method, provide a callback function that takes the current value as its argument:

1
2
const newUsername = 'new username!';
username.update(existing => newUsername);

If you need to add more logic when updating the variable, you can wrap it in a callback function:

1
2
3
4
username.update(existing => {
console.log(`Updating username from ${existing} to ${newUsername}`);
return newUsername;
});

To retrieve the value of the store variable once, use the get() function:

1
2
3
4
import { readable, get } from 'svelte/store';

export const username = writable('Guest');
get(username); // 'Guest'

To create a reactive variable that updates when the stored value changes, prepend the store variable with a $:

1
2
3
import { writable } from 'svelte/store';

export const username = writable('Guest');

Using the $username variable in a component will automatically rerender it whenever the stored value changes.

Alternatively, you can use the subscribe() method of the store variable for more complex logic:

1
2
3
username.subscribe(newValue => {
console.log(newValue);
});

In addition to writable stores, Svelte provides two special kinds of stores: readable stores and derived stores.

Svelte Readable Stores

Readable stores are immutable and cannot be updated from outside. Instead of using the set() or update() methods, you initialize them using the readable() function:

1
2
3
import { readable } from 'svelte/store';

export const count = readable(0);

If you provide a function as the second argument after the default value, it will be responsible for updating the value. This function receives a set function to modify the value:

1
2
3
4
5
6
7
import { readable } from 'svelte/store';

export const count = readable(0, set => {
setTimeout(() => {
set(1);
}, 1000);
});

In this example, the value of count changes from 0 to 1 after 1 second. You can also set up an interval for continuous updates:

1
2
3
4
5
6
7
import { readable, get } from 'svelte/store';

export const count = readable(0, set => {
setInterval(() => {
set(get(count) + 1);
}, 1000);
});

You can access a readable store in another component by importing it:

1
import { count } from './store.js';

Svelte Derived Stores

Derived stores allow you to create a new store value that depends on an existing store value. To create a derived store, use the derived() function exported by svelte/store. The first parameter is the existing store value, and the second parameter is a function that receives the existing store value as its first parameter:

1
2
3
4
5
6
7
import { writable, derived } from 'svelte/store';

export const username = writable('Guest');

export const welcomeMessage = derived(username, $username => {
return `Welcome ${$username}`;
});

You can use the derived store in another component:

1
import { username, welcomeMessage } from './store.js';

I hope this article has helped you understand how to handle cross-component state management in Svelte using props, the Context API, and Svelte stores. These techniques will empower you to build more complex and interactive Svelte applications.

Tags: Svelte, state management, props, Context API, Svelte stores