簡體   English   中英

Laravel Livewire wire:點擊創建無限循環

[英]Laravel Livewire wire:click creates infinite loop

我有一個 Livewire 組件,它是一個產品過濾器。 查詢一切正常,但有時它會創建一個無限循環的請求。

您可以在下面的 GIF 中看到這種情況,它是 Laravel 調試欄的捕獲。 我點擊了一些過濾器,然后它突然進入了這個請求循環。

在此處輸入圖片說明

我專門在視圖中的過濾器上使用了wire:loading.attr="disabled"以便在請求仍在處理時有人無法選擇過濾器。

我的代碼和一些背景:

火線組件

use App\Models\Product;
use App\Models\Brand;
use App\Models\Color;

class SearchProducts extends Component
{
    public ?array $brand = [];
    public ?array $color = [];

    protected $queryString = ['brand', 'color'];

    public function render()
    {
        $products = Product::query();

        $products = $products->with('brand');
        $products = $products->with('colors');

        $products = $this->filterBrands($products);
        $products = $this->filterColors($products);

        $products = $products->paginate(24);

        return view('livewire.search-products', [
            'all_brands' => Brand::where('status', 'active')->get(),
            'all_colors' => Color::where('status', 'active')->get(),
        ])->extends('app');
    }

    public function filterBrands($query)
    {
        $queryFilterBrand = array_filter($this->brand);
        
        return empty($queryFilterBrand) ? $query : $query->whereIn('brand_id', $queryFilterBrand);
    }

    public function filterColors($query)
    {
        $queryFilterColor = array_filter($this->color);

        return empty($queryFilterColor) ? $query : $query->whereHas('colors', function ($q) use ($queryFilterColor) {
            $q->whereIn('color_id', $queryFilterColor);
        });
    }

}

我使用array_filter的原因是因為如果我取消選擇一個顏色值並在鍵中使用一個字符( wire:model="brand.b{{ $brand->id }}" ),而不是從數組 Livewire 中刪除它將該鍵值設置為false 那么這個false值將被放入查詢中,這將給出不准確的結果。

Livewire 視圖和問題

這工作正常:

@foreach($all_brands as $brand)
    <input type="checkbox" value="{{ $brand->id }}" id="brand.{{ $brand->id }}" wire:model="brand.{{ $brand->id }}" wire:loading.attr="disabled">
    <label class="search-label search-wide-label mb-2" for="brand.{{ $brand->id }}">{{ $brand->title }} <i class="fal fa-times float-right selected-icon"></i></label>
@endforeach

但是,當我依次選擇 2 種或更多顏色時,或者選擇 1 種顏色然后取消選擇時,這會產生無限循環。 所以似乎問題發生在第二次交互之后:

@foreach($all_colors as $color)
    <input type="checkbox" value="{{ $color->id }}" id="color.{{ $color->id }}" wire:model="color.{{ $color->id }}" wire:loading.attr="disabled">
    <label class="search-label search-wide-label mb-2" for="color.{{ $color->id }}">{{ $color->title }} <i class="fal fa-times float-right selected-icon"></i></label>
@endforeach

這很奇怪,因為這個刀片片段與上面顯示的$brands完全相同:

唯一不同的是, colors關系是brandhasManybelongsTo

我現在想這就是問題所在......

我嘗試過但沒有用的東西

  • 刪除$all_colors@foreach循環,並將過濾器放在純 HTML 中(檢查問題是否與循環有關)
  • wire:key="brand.{{ $brand->id }}"input元素
  • wire:key="brand.{{ $brand->id }}"input元素周圍的div
  • 使用wire:model="brand.{{ $brand->id }}"wire:model="brand.{{ $loop->id }}"作為評論中的建議(我認為解決了問題)
  • 使用wire:model="brand.b{{ $brand->id }}"所以有一個唯一的鍵名
  • 刪除array_filter方法(這似乎不太可能是問題,但只是為了測試)
  • 使用按鈕代替復選框
  • 使用deferlazy和/或debounce
  • 付錢請專家來嘗試修復它......

控制台錯誤

最后一部分,只有在無限循環發生時,我才會在控制台中收到此錯誤,因此很可能是原因或結果。

TypeError: null is not an object (evaluating 'directive.value.split')

Unhandled Promise Rejection: TypeError: null is not an object (evaluating 'directive.value.split')

兩者都在LoadingStates.js ,我認為它是一個 Livewire Javascript 文件。

這里似乎發生了錯誤:

function startLoading(els) {
    els.forEach(({ el, directive }) => {
        if (directive.modifiers.includes('class')) {
            let classes = directive.value.split(' ').filter(Boolean)

在 GitHub 問題上回答,復制到這里供其他人查找。


問題是一個morphdom問題。

觸發錯誤和循環的代碼是 wire:loading 標題行和產品行。

原因是,當您選擇兩種或多種顏色時,不會顯示任何結果。 然后會發生什么是您從顯示標題/產品/總計切換到顯示空狀態。

但是 morphdom 默認不知道它應該刪除舊的 div 並添加新的 div。 相反,它試圖將舊的第一個 div“變形”為新的 div。 這意味着 wire:loading 偵聽器在不應注冊時仍會注冊。 因此為什么會出現錯誤和循環。

雖然這是一個簡單的修復。 您需要在定義它們的 div 中添加連線鍵,以便 morphdom 知道它們實際上已經完全改變,並刪除舊的並添加新的。

看看下面這張差異截圖,了解我為讓它工作所做的工作。 我為這個文件中的所有頂級 div 添加了一個連線鍵。

建議每當使用這樣的條件將 wire:keys 添加到條件內的第一級元素時,這樣 morphdom 就知道發生了變化。 這與 VueJS 存在相同的問題,其中循環內需要鍵。

差異截圖

所以事實證明,如果你在這樣的foreach循環中使用wire:model ,你必須這樣寫: wire:model="brand.{{ $brand->id }}" 在文檔中找不到它,所以希望它可以幫助其他人。

更新

無限循環由此解決,但現在發生的情況是,一旦您選擇一個復選框,然后再次單擊它以取消選擇,數組值將設置為零而不是從數組中刪除。 那么whereIn將尋找值為0品牌 ID,該 ID 不會返回結果。

更新 2

循環實際上沒有解決......請參閱原始問題。 懸賞這個 $%$£# 因為浪費了太多時間和咖啡。

我看到的幾個問題:

您對<div>元素和<input>元素使用相同的 wire:key 。 我會保留那些獨一無二的。

此外,您在輸入元素上使用相同的name 這將導致復選框出現問題,因為傳遞給后端的值具有相同的名稱,我相信 livewire 將嘗試基於此進行同步。 inputname字段更改為唯一可能是答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM