How to learn Svelte on a weekend
Tags: svelte, javascript, career, productivity
Published: 2020-05-04 15:54:29

---
title: How to learn Svelte on a weekend
published: true
description: Learning frameworks can be challenging, but if we identify what is necessary to understand it, we can dramatically reduce the learning time.
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/rjau8ks3nzmn4vzf8j8t.png
tags: svelte, javascript, career, productivity
---

I've been working with Vue and Angular for years, and recently I've tried React. I was surprised how easy it was to learn React compared to the previous ones. The straightforward answer would be that React is easier to learn, but I didn't feel that I had to learn fewer things. I thought maybe the way I've learned it made such a big difference. I needed another framework to validate my assumptions. The chosen was Svelte, the newest and smallest of them. I've gathered my thoughts on how to go through the building blocks with the same application. To my greatest surprise, it took me only two days to finish learning Svelte and building the application.

Instead of reading the documentation from start to finish or taking a long video course, I've decided to learn Svelte by building a basic but quite powerful application if appropriately implemented, the [well-known TodoMVC application](http://todomvc.com/). Some of you may say that the TodoMVC is too simple for learning a framework: it can be right if you use a minimal toolset, but not right if you break it down to multiple components with state management and testing.

Learning a framework can be a time-consuming task. What worked for me to speed it up enormously is to break down the process into consumable chapters. Starting with the basic building blocks to more complex ones and reading the necessary parts from the official documentation was the right path. This way, it didn't feel overwhelming, and I always had a little success.

I'll walk you through the building blocks in the same order I've learned them. You can extend this list with extra items, but I think the ones I mention are necessary to understand how the framework works. You can check the final application in [my Github repository](https://github.com/blacksonic/todomvc-svelte). If you want to speed it up with one of the other big frameworks check out my other repositories and follow along the building blocks mentioned below ([Vue](https://github.com/blacksonic/todomvc-vue), [Vue Composition API](https://github.com/blacksonic/todomvc-vue-composition-api), [Angular](https://github.com/blacksonic/todomvc-angular), [React](https://github.com/blacksonic/todomvc-react), [React Hooks](https://github.com/blacksonic/todomvc-react-hooks))

### Component

Components are the building blocks of Svelte applications. We'll start with them and later add state management. If you use the [official template](https://svelte.dev/blog/the-easiest-way-to-get-started) it'll give you a simple component out of the box.

#### Creation

Let's create a static component from scratch. [Docs](https://svelte.dev/docs#Component_format)

```html
<script>console.log('runs once');</script>
<style>.main { display: inline; }</style>
<div class="main">Hello World</div>
```

Components reside in .svelte files, using a superset of HTML. The file contains three parts:

- the `script` tag contains JavaScript that runs once when a component instance is created
- the `style` tag contains CSS scoped to the component
- all other regular HTML tags are considered to be part of the component's template

#### Display and bind

Now we have to make it dynamic by adding state and including it in the template. [Docs](https://svelte.dev/docs#Attributes_and_props)

```html
<script>
  let firstName = 'Chris';
  const countries = ['Canada'];
  let isVisible = true;
</script>
<style>.main { display: inline; }</style>
<div class:main={isVisible}>
  <h1>{firstName}</h1>
  <input name="first_name" value={firstName} />
  {#if isVisible}
    <ul>
      {#each countries as country }
        <li>{country.toUpperCase()}</li>
      {/each}
    </ul>
  {/if}
</div>
```

Every locally declared block-scoped variable is available inside the component's template and can be displayed or assigned to an attribute with curly braces. Conditional statements and loops have a special syntax starting with `{#`. Expressions inside curly braces are treated as Javascript expressions.

#### Modify with interactions

The previous component was dynamic but didn't receive any input from the user. Adding event handlers is a way to make the component interactive. [Docs](https://svelte.dev/docs#on_element_event)

```html
<script>
  let firstName = 'Chris';
  const modifyName = event => (firstName = event.target.value);
</script>
<div>
  <h1>{firstName}</h1>
  <input name="first_name" value={firstName} on:input={modifyName} />
</div>
```

Locally declared variables become reactive by default. Reactivity means if we modify its value, it reacts to changes. Functions declared in the `script` tag can be used for event handling.

#### Parent-child interactions

If we don't intend to put everything into one big component, we'll have to break it down into multiple ones. The components will have a parent-child relationship and communicate through props and events. [Docs](https://svelte.dev/docs#createEventDispatcher)

```html
<script>
  import { createEventDispatcher } from 'svelte';
  const dispatch = createEventDispatcher();

  export let name;
  const modifyName = event => dispatch('modify', event.target.value);
</script>
<div>
  <h1>{name}</h1>
  <input name="first_name" value={name} on:input={modifyName} />
</div>
```

The child component notifies the parent component by triggering an event with the function returned from `createEventDispatcher`. Declaring and exporting a variable enables the parent component to pass down property with the same name. This variable is reactive also: if the parent modifies the value of the property, it makes the variable change its value in the child component.

```html
<script>
  import NameInput from './name-input.svelte';

  let firstName = 'Chris';
  const modifyFirstName = event => firstName = event.detail;
</script>
<div>
  <NameInput name={firstName} on:modify={modifyFirstName} />
</div>
```

The parent component first has to import the child component and reference it with a camel-cased name inside its template. Props are passed down as attributes, and custom events are bound as native event listeners.

#### Lifecycle

Sometimes actions are needed at certain points of the lifecycle of the component like at mounting, updating, etc.

```html
<script>
  import { onMount } from 'svelte';

  let firstName = 'Chris';
  onMount(() => console.log('mounted'));
</script>
<h1>{firstName}</h1>
```

Callbacks passed as an argument to the methods starting with `on` are executed every time that lifecycle event happens.

### State management

When multiple components use the same data and passing down props through multiple layers becomes tedious, a state management library can help solve the problem.

#### Store creation

Svelte has a built-in store implementation, no need to import an external library. [Docs](https://svelte.dev/docs#svelte_store)

```javascript
import { writable, derived } from 'svelte/store';

export const name = writable('Chris');
export const upperCaseName = derived(name, current => current.toUpperCase());
```

We can create a store with the `writable` method. Modified values from the state can be created with the `derived` getter. Whenever the original value changes, it calls the callback inside the `derived` function.

```html
<script>
  import { name, upperCaseName } from './store';

  const modifyName = event => name.set(event.target.value);
</script>
<div>
  <h1>{$upperCaseName}</h1>
  <input name="first_name" value={$name} on:input={modifyName} />
</div>
```

Store values display differ from locally declared variables in the `$` prefix. Behind the scenes, Svelte calls the stores `subscribe` which runs on every value change.

#### Global access

It's important to access the store everywhere in the application. Directly referencing the store is a quick solution but introduces tight coupling between the store and the components. Let's look at how to access the store everywhere with loose coupling. [Docs](https://svelte.dev/docs#setContext)

```html
<script>
  import { setContext } from 'svelte';
  import { name, upperCaseName } from './store';
  import NameInput from './name-input.svelte';

  setContext('name', name);
  setContext('upperCaseName', upperCaseName);
</script>
<div>
  <NameInput />
</div>
```

The `setContext` method creates a context variable that is only accessible inside the component and its children.

```html
<script>
  import { getContext } from 'svelte';
  
  const name = getContext('name');
  const upperCaseName = getContext('upperCaseName');

  const modifyName = event => name.set(event.target.value);
</script>
<div>
  <h1>{$upperCaseName}</h1>
  <input name="first_name" value={$name} on:input={modifyName} />
</div>
```

The context variable (in our case the store) is accessible through the `getContext` method.

### Testing

What else can guarantee the application is running as intended if not tests? Svelte has no recommended way of testing, we have to choose our own tools.

#### Unit

Unit tests are the ones we write for a unit in isolation (component, class, etc.). We can use the [Jest testing framework](https://jestjs.io/) for running the tests. [Docs](https://jestjs.io/docs/en/getting-started)

```html
<script>
  let firstName = 'Chris';
  const modifyName = event => (firstName = event.target.value);
</script>
<div>
  <h1 data-testid="display">{firstName}</h1>
  <input data-testid="input" value={firstName} on:input={modifyName} />
</div>
```

We're reusing the component introduced earlier.

```javascript
import { render } from '@testing-library/svelte';
import NameInput from './name-input.svelte';

describe('CopyRight', () => {
  it('should render component', () => {
    const { getByTestId } = render(NameInput);

    const inputElement = getByTestId('input');
    inputElement.value = 'Alexa';
    fireEvent.input(inputElement);

    expect(getByTestId('display')).toHaveTextContent('Alexa');
  });
});
```

Test-cases are organized with the `describe` block and run by the `it` block. The [Svelte Testing library](https://github.com/testing-library/svelte-testing-library) aims to simplify everyday tasks connected to component testing.

#### End-to-End

End-to-end tests observe the application as a black-box, typically they are run in the browser. We can use the [Cypress testing framework](https://www.cypress.io/) for this task. [Docs](https://docs.cypress.io/)

```javascript
describe('Display Name', () => {
  it('it should change name', () => {
    cy.visit('/');

    cy.contains('h1', 'Chris');

    cy.get('input').type('Alexa');

    cy.contains('h1', 'Alexa');
  });
});
```

The organization of the test-cases is the same with `describe` and `it` blocks. The difference is that we give commands with the global `cy` object.

### Additional areas

The topics we've touched are enough for an entry-level application, but more complex ones need other areas like routing ([docs](https://github.com/EmilTholin/svelte-routing)), request handling ([docs](https://svelte.dev/docs#await)), and animations. My goal was to get an overall understanding of the framework, and I knowingly excluded them as they weren't necessary for it.

### Summary

Learning frameworks can be challenging, but if we identify what is necessary to understand it, we can dramatically reduce the learning time. Creating a list out of what we have to learn makes it consumable and measurable. Not to mention, we always have a little success on the road. I hope it makes you try out a new framework that you have been thinking of.