symfony / ux

Symfony UX initiative: a JavaScript ecosystem for Symfony
https://ux.symfony.com/
MIT License
853 stars 314 forks source link

[LiveComponent] How "defer" option work and the logic behind __invoke #1543

Closed gremo closed 2 months ago

gremo commented 8 months ago

I have a WheaterWidget with a refresh action that can be invoked with the data-pool option or a button click:

#[AsLiveComponent]
class WheaterWidget
{
    public function __invoke(): void
    {
        $this->refresh();
    }

    #[LiveAction]
    public function refresh(): void
    {
        // Update component internal state
    }
}

Here is the behaviour:

  1. With <twig:WheaterWidget defer /> method __invoke is called -> widget is refreshed as soon as it loads
  2. With <twig:WheaterWidget /> method __invoke isn't called -> widget isn't updated

I want to make it work (refreshed as soon as it loads) with or without defer. So I added a [PostMount] attribute to refresh:

#[LiveAction]
#[PostMount]
public function refresh(): void
{
    // Update component internal state
}

And this, indeed, make the widget behave correcly for case 2... but then adding a defer will make it refresh twice (both __invoke and refresh are called).

So what's the correct way to handle this kind of situation?

smnandre commented 8 months ago

You can look at "how" the defer is implemented i think.

It call a "render" action by listening to the "live:connect" event.

Oh but yeah, no you'd be then rendered twice if you use a defer attribute...

Now my question is: what is the goal to render your component and then immediately re-render it ? What i'd like to know is : is there anything with defer annoying or not allowing you to do something ?

I mean, as what you want to achieve is 100% what the defer attribute offers... ?

smnandre commented 8 months ago

With <twig:WheaterWidget /> method __invoke isn't called -> widget isn't updated

__invoke is called when you render the component during the first request

gremo commented 8 months ago

@smnandre

I mean, as what you want to achieve is 100% what the defer attribute offers... ?

The defer will cause a big big layout shift. Sometimes you want to avoid a layout shift (Lighthouse performance metric), trading it with a bit longer loading time. Other times you may want to render the page as quick as possibile, defering some parts of the page. That's why I'd like to make my widget work in both cases.

__invoke is called when you render the component during the first request

I can't reproduce this behaviour... my bad?

smnandre commented 8 months ago

The defer will cause a big big layout shift. Sometimes you want to avoid a layout shift (Lighthouse performance metric), trading it with a bit longer loading time. Other times you may want to render the page as quick as possibile, defering some parts of the page. That's why I'd like to make my widget work in both cases.

I had the same "problem", and i opened this PR this week, i think you will be interested ;)

https://github.com/symfony/ux/pull/1532

smnandre commented 8 months ago

And i have a lazy attribute with intersection observer loading coming next weeks too :)

carsonbot commented 2 months ago

Thank you for this issue. There has not been a lot of activity here for a while. Has this been resolved?

carsonbot commented 2 months ago

Friendly ping? Should this still be open? I will close if I don't hear anything.

gremo commented 2 months ago

Let's close it.