Post

Components, Store with svelte.

Let's learn the basic syntax of svelte.

Components, Store with svelte.

Component

In Svelte, a component is a reusable and independent UI block.
It is the basic unit used to build a user interface.

One of the most important concepts in Svelte components is Props. Props in Svelte are a mechanism to pass data from a parent component to a child component. They allow parent components to send information to child components, making the child components dynamic and reusable.

The structure overview

In the child component (e.g., Child.svelte), use the export let syntax to declare a prop.

1
2
3
4
5
6
<!-- $lib/components/Child.svelte -->
<script>
  export let name;
</script>

<p>Hello, {name}!</p>

In the parent component (e.g., App.svelte), pass the value to the child:

1
2
3
4
5
6
<!-- /src/routes/+page.svelte -->
<script>
  import Child from '$lib/components/Child.svelte';
</script>

<Child name="DS2Man" />
1
2
# Result is ...
Hello, DS2Man!

Examples

  • /src/routes/+page.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<script>
  // Import child components
  // FruitName.svelte: displays fruit name only
  // Fruit.svelte: displays fruit name and color
  import FruitName from '$lib/components/Fruit_name.svelte';
  import Fruit from '$lib/components/Fruit.svelte';

  // Array of fruit names (used in Case 1)
  let fruits_name = ['Apple', 'Banna', 'Cherry', 'Orange', 'Mango'];

  // Array of fruit objects with id, name, and color (used in Case 2 & 3)
  let fruits = [
    { id: 1, name: 'Apple', color: 'red' },
    { id: 2, name: 'Banna', color: 'yellow' },
    { id: 3, name: 'Cherry', color: 'blue' },
    { id: 4, name: 'Orange', color: 'orange' },
    { id: 5, name: 'Mango', color: 'orange' }
  ];
</script>

<main>
  <div class="grid-container">
    <!-- Case 1 -->
    <div class="column">
      <h3>Case 1</h3>
      <ol>
        {#each fruits_name as fruit_name}          
          <!-- 
            Passing the variable 'fruit_name' as a prop
            to the FruitName component.
            Since the variable name and prop name are the same,
            we can use shorthand: {fruit_name}
            In FruitName.svelte, it will be received like:
            export let fruit_name;
          -->
          <!-- 
            <FruitName fruit_name={fruit_name} /> 
            If the attribute name and the data (variable) name are the same, 
            you can simplify the code as shown below.
          -->
          <FruitName {fruit_name} />
        {/each}
      </ol>
    </div>

    <!-- Case 2 -->
    <div class="column">
      <h3>Case 2</h3>
      <ul>
        {#each fruits as fruit (fruit.id)}
          <!-- 
            Passing two props: 'fruit' and 'color'
            to the Fruit component.
            The parent passes data down to the child.
            In Fruit.svelte, it will be received like:
            export let fruit;
            export let color;
          -->
          <Fruit name={fruit.name} color={fruit.color} />
        {/each}
      </ul>
    </div>

    <!-- Case 3 -->
    <div class="column">
      <h3>Case 3</h3>
      <ul>
        {#each fruits as { name, color } (name)}
          <!-- 
            Using destructuring to directly extract 'name' and 'color'
            from the fruits array, and passing them as props.
            This is another clean way to pass multiple props.
          -->
          <!-- 
            <Fruit name={name} color={color} />
            If the attribute name and the data (variable) name are the same, 
            you can simplify the code as shown below.
          -->
          <Fruit {name} {color} />
        {/each}
      </ul>
    </div>
  </div>
</main>

<style>
  .grid-container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
  }

  .column {
    border: 1px solid black;
    padding: 10px;
  }
</style>
  • Fruit.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
  // Declare props (properties) to receive data from the parent component
  // 'name' prop: will receive the fruit name
  export let name
  // 'color' prop: will receive the fruit color
  export let color
</script>

<main>
  <li style="color: {color};">{name}</li>    
</main>

<style>
</style>
  • Fruit_name.svelte
1
2
3
4
5
6
7
8
9
10
11
12
<script>
  // Declare props (properties) to receive data from the parent component
  // 'fruit_name' prop: will receive the fruit name
  export let fruit_name
</script>

<main>
  <li>{fruit_name}</li>    
</main>

<style>
</style>

Result Result

Store

Store is a state management system provided by the Svelte framework. It allows you to store state values that can be accessed and shared globally across components.

Problem Examples

The components App.svelte, Parent.svelte, and Child.svelte are properly using props and bind to update the name value in App.svelte. There is no major issue with this structure.
However, let’s consider the following scenario:
Suppose that in Parent.svelte, there is no need to use or manage the name value, but in Child.svelte, the name value needs to be updated. With the current structure, you are forced to define and pass the name prop in Parent.svelte, even though it doesn’t actually need it. This leads to an unnecessary and redundant structure. Furthermore, as the number of components grows, this issue becomes more serious and can cause increased complexity in your component hierarchy.
This issue can be improved by using a store.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- +/src/routes/+page.svelte -->
<script>
  import Parent from '$lib/components/Parent.svelte'
  let name = "DS2Man"

</script>

<main>
  <h1>Hello, {name}</h1>
  <Parent bind:name={name}/>
</main>

<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- $lib/components/Parent.svelte -->
<script>
  import Child from '$lib/components/Child.svelte'
  export let name
  let isActive = true

  const toggle = () => {
    if (isActive === true)
      name="Parent"
    else
      name="DS2Man"
    isActive = !isActive
  }
</script>

<main>
  <button on:click={toggle}>Parent!</button>   
  <Child bind:name={name} />
</main>

<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
<!-- $lib/components/Child.svelte -->
<script>
  export let name
</script>

<main>
  <button on:click={() => {name="Child"}}>Child!</button>   
</main>

<style>
</style>

Solution : Using a Svelte Store

To solve this problem, we can use Svelte’s store system.
A store in Svelte is a simple and reactive way to manage and share state outside of the component hierarchy.
This allows any component to access and update shared data directly, without having to pass it through intermediate components.
In our example, we created a writable store named name and used it in App.svelte, Parent.svelte, and Child.svelte.

1
2
3
4
5
6
7
8
// $lib/stores/Store.ts

// Import writable store from Svelte's store module
import { writable } from 'svelte/store';

// Create a writable store named 'name'
// It holds a string value and can be updated
export let name = writable('DS2Man');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- /src/routes/+page.svelte -->
<script>
  import Parent from '$lib/components/Parent.svelte'
  import { name } from '$lib/stores/Store.ts'
</script>

<main>
  <!-- 
    To read a store value, use the $ prefix.
    Here, $name will automatically update whenever the store value changes.
  -->
  <h1>Hello, {$name}</h1>

  <Parent />
</main>

<style>
</style>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!-- '$lib/components/Parent.svelte -->
<script>
  import Child from '$lib/components/Child.svelte'
  import { name } from '$lib/stores/Store.ts'

  let isActive = true

  const toggle = () => {
    if (isActive === true)
      // $name="Parent"
      name.set("Parent")
    else
      // $name="DS2Man"
      name.set("DS2Man")
    isActive = !isActive
  }
</script>

<main>
  <button on:click={toggle}>Parent!</button>   
  <Child />
</main>

<style>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- '$lib/components/Child.svelte -->
<script>
  import { name } from '$lib/stores/Store.ts' // Import the 'name' store
</script>

<main>
  <!-- 
    When this button is clicked, the store value will be updated to "Child".
    All components using $name will automatically update.
  -->
  <button on:click={() => {name.set("Child")}}>Child!</button>
</main>

<style>
</style>

Result Result

This post is licensed under CC BY 4.0 by the author.