skip to Main Content

I have a Laravel Livewire model which has two public properties:

  • A string called $tab (which I used to switch between UI tabs)
  • A Model called $myobject (with relationships).

Whenever I retrieve my $myobject model, I use the Cache::remember function to retrieve my model from my Redis cache if it’s in there – this all works perfectly in the Livewire model (mount) and in my Controllers.

However, if I change the $tab property on my Livewire model (either through an $emit, or wire:click, etc) this causes the $myobject model to be ‘rehydrated’ from the database (and not the cache), causing unnecessary database queries (as it’s already in the cache).

I can see this happening using using DebugBar:

8 statements were executed, 6 of which were duplicated, 2 unique.
...
select * from `model` where `models`.`id` = 1 limit 1
350μs

/vendor/laravel/framework/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php:108
...

I understand that Livewire is ‘stateless’ and hence needs to pass all public properties to/from the browser when anything changes… however is there a way of intercepting the rehydration, so that I can make my $myobject from the cache (I’m happy to write this function), rather than doing expensive DB queries to retrieve it and it’s relationships?

The SerializesAndRestoresModelIdentifiers.php script seems to be the culprit in running the queries.

I’m not really sure why it’s having to do these queries, as isn’t all the data being returned from the browser?

2

Answers


  1. Did you consider trying something like:

    public function updatedTab($data) {
       // Here you can get the data from the cache and you provide data if you need to send something to the component class. - This fires every time tab changes value
    }
    

    Tbh this is the way I’d go with and if you need to run mount and it works fine then I guess you could basically use:

    public function updatedTab() {
       $this->mount();
    }
    

    This is just from top of my head 🙂

    Login or Signup to reply.
  2. There is a little workaround/hack to achieve this. Any public property will be dehydrated and rehydrated everytime a request comes full circle. It has to do a query to be able to get the model, since Livewire is indeed stateless. However, protected and private properties are not hydrated. So, what you can do is the following:

    class YourComponent Extends Component
    {
        protected Model $yourModel;
    
        public function mount()
        {
            $this->getModel();
        }
    
        public function render()
        {
            return view('your-view', ['model' => $this->model]);
        }
    
        public function hydrate()
        {
            $this->getModel();
        }
    
        public function getModel()
        {
            $this->model = Cache::remember('yourKey', 100, function () {
                return Model::find(10);
            });
        }    
    }
    

    Hydrate gets called right after hydrating the component, but before anything else. This allows you to reset your model field, before anything might have to access it. You’ll have to manually pass it to the view within the render method, as Livewire won’t pass it on automatically. This way, you can fetch it from cache instead of having Livewire query the database each time.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search