eakl
eakl

Reputation: 571

Svelte component doesn't re-render when its props change

I'm new to Svelte and coming from React, I am not sure I understand Svelte reactivity correctly.

Let's say I have a Parent component that fetches data asynchronously and passes the data to its Child component.

<!-- Parent -->
<script>
    import { onMount } from 'svelte'
    import Nested from './Nested.svelte'
    
    let options = []
    $: console.log('Parent-options', options)
    
    onMount(async () => {
        options = await Promise.resolve([1, 2, 3])
    })
</script>

<div>
    <Nested {options} />
</div>
<!-- Child -->
<script>
    const { options, ...restProps } = $$props
    $: console.log('Child-options', options)
</script>

<div>
    The value is {options}
</div>

As you can see the console.log, both the Parent and the Child components log an empty array. Then the Parent component logs the fetched data. But the Child component never re-renders with the updated data.

EDIT: Exposing props is done with the export keyword.

export let options

and svelte documentation states

$$props references all props that are passed to a component, including ones that are not declared with export. It is not generally recommended, as it is difficult for Svelte to optimise. But it can be useful in rare cases – for example, when you don't know at compile time what props might be passed to a component.

But in fact I'm wrapping a <select> component so I don't know the number of props that will be passed before compile time. Hence I use $$props instead of listing them all.

In typescript this is my types

import type { HTMLSelectAttributes } from 'svelte/elements'

type Option = {
  id: string
  value: string
  label: string
}

type $$Props = HTMLSelectAttributes & {
  options: Option[]
}

What is the correct way to receive an arbitrary number of props in the Child components?

Available REPL: https://svelte.dev/repl/849468dd89f143fdbf8a12dd16568647?version=3.55.1

Upvotes: 0

Views: 2405

Answers (1)

brunnerh
brunnerh

Reputation: 184376

When you use const, the value will never change after the first assignment:

const { options, ...restProps } = $$props

That destructuring has to be reactive as well:

$: ({ options, ...restProps } = $$props);

If you know that you need options, you can just export that explicitly. Svelte already provides a special value $$restProps that contains everything that is not exported.

Upvotes: 1

Related Questions