You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte/site/content/guide/18-advanced.md

3.8 KiB

title
Advanced

Keyed each blocks

Associating a key with a block allows Svelte to be smarter about how it adds and removes items to and from a list. To do so, add an (expression) that uniquely identifies each member of the list:

<!-- { repl: false } -->
{#each people as person (person.name)}
	<div>{person.name}</div>
{/each}

It's easier to show the effect of this than to describe it. Open the following example in the REPL:

<!-- { title: 'Keyed each blocks' } -->
<button on:click="{update}">update</button>

<section>
	<h2>Keyed</h2>
	{#each people as person (person.name)}
		<div transition:slide>{person.name}</div>
	{/each}
</section>

<section>
	<h2>Non-keyed</h2>
	{#each people as person}
		<div transition:slide>{person.name}</div>
	{/each}
</section>

<style>
	button {
		display: block;
	}

	section {
		width: 10em;
		float: left;
	}
</style>

<script>
	import { slide } from 'svelte/transition';

	const names = ['Alice', 'Barry', 'Cecilia', 'Douglas', 'Eleanor', 'Felix', 'Grace', 'Horatio', 'Isabelle'];

	function random() {
		return names
			.filter(() => Math.random() < 0.5)
			.map(name => ({ name }));
	}

	let people = random();

	function update() {
		people = random();
	}
</script>

Hydration

If you're using server-side rendering, it's likely that you'll need to create a client-side version of your app on top of the server-rendered version. A naive way to do that would involve removing all the existing DOM and rendering the client-side app in its place:

import App from './App.html';

const target = document.querySelector('#element-with-server-rendered-html');

// avoid doing this!
target.innerHTML = '';
new App({
	target
});

Ideally, we want to reuse the existing DOM instead. This process is called hydration. First, we need to tell the compiler to include the code necessary for hydration to work by passing the hydratable: true option:

const { js } = svelte.compile(source, {
	hydratable: true
});

(Most likely, you'll be passing this option to rollup-plugin-svelte or svelte-loader.)

Then, when we instantiate the client-side component, we tell it to use the existing DOM with hydrate: true:

import App from './App.html';

const target = document.querySelector('#element-with-server-rendered-html');

new App({
	target,
	hydrate: true
});

It doesn't matter if the client-side app doesn't perfectly match the server-rendered HTML — Svelte will repair the DOM as it goes.

Immutable

Because arrays and objects are mutable, Svelte must err on the side of caution when deciding whether or not to update things that refer to them.

But if all your data is immutable, you can use the { immutable: true } compiler option to use strict object comparison (using ===) everywhere in your app. If you have one component that uses immutable data you can set it to use the strict comparison for just that component.

In the example below, searchResults would normally be recalculated whenever items might have changed, but with immutable: true it will only update when items has definitely changed. This can improve the performance of your app.

<!-- { repl: false } -->
{#each searchResults as item}
	<div>{item.name}</div>
{/each}

<script>
	import FuzzySearch from 'fuzzy-search';

	export default {
		immutable: true,

		computed: {
			searchResults: ({ searchString, items }) => {
				if (!searchString) return items;

				const searcher = new FuzzySearch(items, ['name', 'location']);
				return searcher.search(searchString);
			}
		}
	}
</script>

Here's a live example showing the effect of immutable: true.