Laravel Livewire 线:点击创建无限循环

esk*_*imo 3 laravel laravel-livewire

我有一个 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);
        });
    }

}
Run Code Online (Sandbox Code Playgroud)

我使用的原因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
Run Code Online (Sandbox Code Playgroud)

但是,当我依次选择 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
Run Code Online (Sandbox Code Playgroud)

这很奇怪,因为这个刀片片段与上面所示的完全相同$brands

唯一不同的是,这种colors关系是 ahasMany与 a belongsTofor brand

我现在想,问题就出在这里……

我尝试过但没有成功的事情

  • 删除@foreach循环$all_colors并将过滤器放入纯 HTML 中(以检查问题是否与循环有关)
  • 添加wire:key="brand.{{ $brand->id }}"input元素
  • 添加wire:key="brand.{{ $brand->id }}"到元素div周围input
  • 使用wire:model="brand.{{ $brand->id }}"wire:model="brand.{{ $loop->id }}"按照评论中的建议(以及我认为解决了问题的方法)
  • 使用wire:model="brand.b{{ $brand->id }}"这样就有一个唯一的键名
  • 删除该array_filter方法(似乎这不太可能是问题,但只是为了测试)
  • 使用按钮而不是复选框
  • 使用defer,lazy和/或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 文件。

那里的错误似乎发生在这里:

@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
Run Code Online (Sandbox Code Playgroud)

小智 6

在 GitHub 问题上回答,复制到这里以便其他人能够找到。


问题是形态问题。

触发错误和循环的代码是标题行和产品行上的wire:loading。

原因是,当您选择两种或多种颜色时,不会显示结果。然后发生的事情是您从显示标题/产品/总计切换为显示空状态。

但 morphdom 默认情况下并不知道它应该删除旧的 div 并添加新的 div。相反,它试图将旧的第一个 div“变形”为新的。这意味着,wire:loading 监听器在不应该注册的情况下仍然被注册。这就是为什么会出现错误和循环。

但这是一个简单的修复。您需要将线键添加到定义它们是什么的 div 中,以便 morphdom 知道它们实际上已完全更改,并删除旧的并添加新的。

看看下面的差异截图,了解我为使其正常工作所做的工作。我为该文件中的所有顶级 div 添加了一个线键。

建议每当使用这样的条件时,将wire:keys 添加到条件中第一级的任何元素,以便 morphdom 知道发生了更改。VueJS 也有同样的问题,循环内需要键。

差异截图