sveltejs / svelte

web development for the rest of us
https://svelte.dev
MIT License
79.75k stars 4.23k forks source link

Transferring values from a layout to pages, or to components, and back #14051

Open Gorbulev-Sergey opened 5 days ago

Gorbulev-Sergey commented 5 days ago

Describe the problem

I know that you have a lot to do without me! Guys, I think it's very important to have functionality: to directly transfer values from the layout to pages, to components and back, from bottom to top. I know that you can use store or context, but it's inconvenient: context is limited in principle, and if you load the store with data from all components or pages, you can get confused about where the data comes from.

Describe the proposed solution

In children or component:

let {parent} = $props();
let myValueFromParent = parent.myValue;
myValueFromParent = "New value";

or

let myValueFromParent = $parent().myValue;
myValueFromParent = "New value";

or

let myValueFromParent = $parent(v=>v.myValue);
myValueFromParent = "New value";

In parent or layout:

let {children} = $props();
let myValueFromChildren = children.myValue;
myValueFromChildren = "New value";

or

let myValueFromChildren = $children().myValue;
myValueFromChildren = "New value";

or

let myValueFromChildren = $children(v=>v.myValue);
myValueFromChildren = "New value";

Importance

would make my life easier

Leonidaz commented 5 days ago

Note: This example is outdated. Please see the comment below a this is not quite correct as Svelte encourages using bind: and $bindable().

Would this work for you? (using Svelte 5)

Playground: Child to Parent

Parent:

<script>
    import Child from './Child.svelte';
    let parent = $state({myValue: 'from parent with love'});
</script>

<h1>Hello {parent.myValue}!</h1>

<Child {parent} />

Child:

<svelte:options runes />
<script>
    let { parent } = $props();
    let myValueFromParent = $derived(parent.myValue);

    parent.myValue = "from Child";
</script>

<div>
    {myValueFromParent}
</div>
Leonidaz commented 5 days ago

Actually, a more explicit way of indicating that a prop can be changed by the child is by using $bindable() rune and bind:prop.

Playground Demo: Child to Parent via bind and $bindable()

This also avoids a warning from Svelte as in the previous example:

[svelte] ownership_invalid_mutation Child.svelte mutated a value owned by App.svelte. This is strongly discouraged. Consider passing values to child components withbind:, or use a callback instead

Gorbulev-Sergey commented 4 days ago

Guys, thank you for your attention to my question. I searched the Internet a bit and played with the code, and your code also became a confirmation of what I found on the Internet. It turns out that there is a data transfer mechanism between the page and the component, and you can make a two-way binding. And how can data be exchanged between a layout and a page without using store and context?

Gorbulev-Sergey commented 4 days ago

Actually, a more explicit way of indicating that a prop can be changed by the child is by using $bindable() rune and bind:prop.

Playground Demo: Child to Parent via bind and $bindable()

This also avoids a warning from Svelte as in the previous example:

[svelte] ownership_invalid_mutation Child.svelte mutated a value owned by App.svelte. This is strongly discouraged. Consider passing values to child components withbind:, or use a callback instead

Leonidaz, thank you for your attention to my question. I searched the Internet a bit and played with the code, and your code also became a confirmation of what I found on the Internet. It turns out that there is a data transfer mechanism between the page and the component, and you can make a two-way binding. And how can data be exchanged between a layout and a page without using store and context?

Leonidaz commented 3 days ago

Actually, a more explicit way of indicating that a prop can be changed by the child is by using $bindable() rune and bind:prop. Playground Demo: Child to Parent via bind and $bindable() This also avoids a warning from Svelte as in the previous example: [svelte] ownership_invalid_mutation Child.svelte mutated a value owned by App.svelte. This is strongly discouraged. Consider passing values to child components withbind:, or use a callback instead

Leonidaz, thank you for your attention to my question. I searched the Internet a bit and played with the code, and your code also became a confirmation of what I found on the Internet. It turns out that there is a data transfer mechanism between the page and the component, and you can make a two-way binding. And how can data be exchanged between a layout and a page without using store and context?

Please see the discussion on the same subject. I created a couple of examples in addition to the solutions that were already provided: Discussion