Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Svelte page component instance is not refreshed #1670

Open
edgars-vasiljevs opened this issue Sep 9, 2023 · 12 comments
Open

Svelte page component instance is not refreshed #1670

edgars-vasiljevs opened this issue Sep 9, 2023 · 12 comments
Assignees
Labels
bug Something isn't working svelte Related to the svelte adapter

Comments

@edgars-vasiljevs
Copy link
Contributor

Version:

  • @inertiajs/svelte version: 1.0.11

Describe the problem:

Page component is not refreshed (destroyed and recreated) when navigating to the same page.

Per documentation page component is supposed to refresh - "By default, page visits to the same page create a fresh page component instance."

Steps to reproduce:

  • fresh laravel + inertia + svelte install
  • routes:
Route::get('/1', function () {
    return Inertia::render('Index', [ 'name' => 'Foo' ]);
});
Route::get('/2', function () {
    return Inertia::render('Index', [ 'name' => 'Bar' ]);
});
  • Index.svelte
<script>
    import { useForm, inertia } from '@inertiajs/svelte'
    export let name;
    
    const form = useForm({
        'name': name
    });

    $: console.log('Name property updated?', name); // this runs
</script>

Name: <input type="text" bind:value={$form.name} >

<a use:inertia href="/1">Link to Foo</a>
<a use:inertia href="/2">Link to Bar</a>

Currently only exported properties are updated but page component instance stays the same.
This causes an issue where form is not updated when navigating to the same form but with different data.

Tried same scenario with Vue2 and it's updating form as expected. Component is being re-mounted every time.

  • Index.vue
<template>
  <div>
    Name: <input type="text" v-model="form.name"><br />
    <Link href="/1">Link to Foo</Link><br />
    <Link href="/2">Link to Bar</Link><br />
  </div>
</template>

<script>
import { Link } from '@inertiajs/vue2'
export default {
  components: { Link },
  props: { name: String },
  remember: 'form',
  data() {
    return {
      form: this.$inertia.form({
        name: this.name,
      }),
    }
  },
   mounted() {
    console.log('component is being (re)mounted')
   }
}
</script>
@edgars-vasiljevs edgars-vasiljevs added the svelte Related to the svelte adapter label Sep 9, 2023
@edgars-vasiljevs
Copy link
Contributor Author

Not quite confident making PR but here is a fix I came up with and deployed to prod. It has been running for couple of weeks now and I haven't noticed any issues so far - https://github.com/edgars-vasiljevs/inertiajs-svelte/pull/1/files

It uses #key logic block to re-render page component whenever component's key changes.
It checks whether swapped component is the same as current one and component has no children (is not layout).

Hope this gives more clues.

@ianautiyal
Copy link

anyone any update on this?

@danielstgt
Copy link
Contributor

@edgars-vasiljevs Thank you for your fix! I can confirm that your changes work, I think it's safe to create a PR.

@driesvints
Copy link
Contributor

Seems a PR was sent in so let's see how it goes. Thanks all.

@reinink
Copy link
Member

reinink commented Apr 16, 2024

This has been fixed in #1763 has been released as part of v1.0.16 👍

@edgars-vasiljevs
Copy link
Contributor Author

Issue is still present in latest release.
New component instance is not created when navigating to the same page component.

See my original post for steps on how to reproduce. I expect const form = useForm({..}); to re-run every time I navigate to the same page component. In my example, you can navigate between two links but $form will hold value from initial full page load.

@danielstgt
Copy link
Contributor

The proposed fix from #1763 isn't working for me either, reverted back to @edgars-vasiljevs solution.

@danielstgt
Copy link
Contributor

@reinink @driesvints can we reopen this issue?

@reinink reinink reopened this May 29, 2024
@reinink
Copy link
Member

reinink commented May 29, 2024

Yup, reopened.

To be honest I've never been able to reproduce this issue locally myself, can any provide a minimal reproduction using our Svelte playground (https://github.com/inertiajs/inertia/tree/master/playgrounds/svelte)? That would help me a ton, as it's impossible to fix something I can't reproduce.

@vits
Copy link

vits commented Jun 12, 2024

Hi! Found this issue while preparing to submit my own on this bug. Was going to name it - inertiajs-svelte ignores preserveState option and works as if it is always true. Minimal reproduction is simple inertia page like this

<script>
  import { router } from "@inertiajs/svelte";
  let count = 0;
  const increase = () => count += 1;
  // same page url here to make revisit, preserveState: false is not needed as it should be default, `
  const reload = () => router.visit('/page', { preserveState: false }); 
</script>

<button on:click={increase}>{count}</button>
<button on:click={reload}>reload</button>

Try this and you'll see that counter value ir preserved between visits, which is different from other framework behaviour and makes preserveState value useless and. I believe source of this is the same problem as OP.

In fact I have solution as well. Studied vue version and tried to apply $store.key value (which is changed on every visit if preserveState is false) aproximately the same way. Sorry, no PR, just code snippets.

Made new component Key.svelte to wrap page component.

<script>
  export let key = null;
</script>

{#key key}<slot />{/key}

and then changed $: child ... in App.svelte to wrap page component (but not layout!) with this component

import Key from "./Key.svelte";
...
$: child =
  $store.component && h(Key, { key: $store.key }, [
    h($store.component.default, $store.page.props),
  ]);

Hope this helps.

@rkyoku
Copy link

rkyoku commented Aug 22, 2024

I am experiencing the same issue.

I have several pages, say /entity/A and /entity/B, but when I use a link (standard a link using use:inertia or Link component, doesn't matter) to go to the other entity, it is the same component, and therefore Inertia doesn't trigger a re-render.

The same happens when I click on a link to change the language of the current page (e.g. from /fr/entity/A to /en/entity/A)

Do you have a Band-Aid solution to trigger a full (including layout etc.) re-render whenever the URL changes? IMHO it makes no sense to preserve the current state when the URL changes.

EDIT: also, the props (export let something;) don't seem to be updated. I tried debugging them in a reactive statement that triggered after clicking the link, and they are keeping the same values as before

@rkyoku
Copy link

rkyoku commented Aug 22, 2024

For now, the only band-aid I found:

I am removing all the export let prop from my templates and I exclusively rely on reactive blocks based on $page.props (maybe some people solely do this, that's why they were not bothered by this bug).

It seems to do the trick (at a small cost of extra code for more complex cases).

does not work

export let prop1;

works

$: prop1 = $page.props.prop1;

works too, for more complex needs

let prop1;
let prop2;

function updateState() {
    prop1 = $page.props.prop1;
    prop2 = $page.props.prop2;
    // do some more stuff here
    // (maybe some stuff that don't belong to a reactive block, in order to prevent unnecessary triggers of that reactive block)
}

$: $page.props && updateState();

I am new to Svelte / Inertia so please forgive me if this solution is not completely elegant or optimized

EDIT: there seems to be caveats, as now that I made this change, whenever I leave this page (aka "main component") to another one, Inertia still tries to refresh this page (whereas it should be discarded, as a new "main component" was returned from the ajax query). E.g. I first-load page /hello which uses main-component pages/Hello.svelte; I then click a link to switch to another page, say /play which uses main-component pages/Play.svelte, but Inertia still tries to refresh pages/Hello.svelte (maybe because of the reactive statement on $page.props that I added as a band-aid, see above...) ; I fixed it by putting my whole page in a big {#if} statement based on one of my page-specific props; it is ugly but it works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working svelte Related to the svelte adapter
Projects
None yet
Development

No branches or pull requests

8 participants