gpt4 book ai didi

Laravel Livewire 电线 :click creates infinite loop

转载 作者:行者123 更新时间:2023-12-04 02:30:07 26 4
gpt4 key购买 nike

我有一个 Livewire 组件,它是一个产品过滤器。查询都可以正常工作,但有时会产生无限的请求循环。

您可以在下面的 GIF 中看到发生的情况,它是 Laravel 调试栏的捕获。我正在单击一些过滤器,然后突然进入此请求循环。

enter image description here

我特别在 View 中的过滤器上使用了 wire:loading.attr="disabled",这样当请求仍在处理时,某人就无法选择过滤器。

我的代码和一些背景:

Livewire 组件

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

这很奇怪,因为这个 Blade 代码片段与上面显示的 $brands 完全相同:

唯一不同的是 colors 关系是 hasManybrandbelongsTo

我现在认为这就是问题所在...

我试过但没用的东西

  • 移除 $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 不是一个对象(正在评估'directive.value.split')

未处理的 Promise 拒绝:TypeError:null 不是一个对象(评估“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 问题上的回答,复制到这里以供其他人找到。


问题是形态问题。

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

原因是,当您选择两种或多种颜色时,没有显示结果。然后会发生什么,您将从显示标题/产品/总计切换到显示空状态。

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

虽然这是一个简单的修复。您需要向定义它们的 div 添加线键,以便 morphdom 知道它们实际上已经完全改变,并删除旧的并添加新的。

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

建议每当使用这样的条件时,将 wire:keys 添加到条件内第一层的任何元素,以便 morphdom 知道发生了变化。这与 VueJS 存在的问题相同,循环内需要键。

Screenshot of diff

关于Laravel Livewire 电线 :click creates infinite loop,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64731832/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com