Livewire 在尝试水合……组件时遇到损坏的数据

Livewire encountered corrupt data when trying to hydrate the … component

我收到以下错误并且有点迷茫:

Livewire encountered corrupt data when trying to hydrate the … component. Ensure that the [name, id, data] of the Livewire component wasn’t tampered with between requests

情况如下:Livewire 2.x, Laravel 7.x, Component Controller从3个MySQL Stored Procedures中获取数据并进行处理。组件 Blade 是一个非常基本的 blade,带有 foreach 循环。我正在使用 wire:init 功能,以便该组件不会阻止页面加载。它包含一个 custom-built 分页。当切换到第二页数据时,出现这个错误。在 Livewire 1.x.

上没有出错

有人知道如何解决这个问题吗?错误本身对我来说意义不大。需要任何其他信息吗?

提前致谢,感谢您的帮助!

在我的例子中,解决方案是使 public 属性 受保护并手动将其传递给 blade,因此它被排除在 Livewire 的 auto-handling 下引擎盖。

所以我遇到了同样的错误,这个错误:

Livewire encountered corrupt data when trying to hydrate the [component] component. Ensure that the [name, id, data] of the Livewire component wasn't tampered with between requests.

在尝试接受答案并阅读 Livewire 的 Github 上的 this long issue thread 后,我尝试以不同的方式将数据传递给视图。我在这里分享它是为了帮助其他有相同用例问题的人。

我发现了以下变化,其中 url 我之前经过的地方我只是进入了视图,让它消失了。来自:

// Class
class MyComponent extends Component
{
    public Shop $shop;
    public Address $address;
    public string $action;

    // rules etc

    public function mount(Shop $shop)
    {
        if ($shop->address()->exists()) {
            $this->address = $shop->address;
            $this->form_action = route('merchant.shop.address.update');
        } else {
            $this->address = Address::make();
            $this->form_action = route('address.store');
        }
    }

// view
<div>
    <form method="post" action="{{ $action }}">
        @csrf

至:

// class
class MyComponent extends Component
{
    public Shop $shop;
    public Address $address;

    // rules etc

    public function mount(Shop $shop)
    {
        $this->address = $shop->address()->exists() ? $shop->address : Address::make();
    }

// view
<div>
    <form method="post" action="{{ $shop->address()->exists() ? route('merchant.shop.address.update') : route('address.store') }}">

在我的例子中,我有几个 public 变量,但并非所有变量都是从父视图传入的。阅读马库斯的回答后。我去将 mount 方法添加到我的 livewire class 并传入了我从父级继承的变量并且它起作用了。我正在使用 Livewire 2.3

这里有错误

class MyView extends Component
{
  public $fromParent, $local;

  public function render()
  {
    return view('livewire.my-view');
  }
}

添加挂载修复了它

class MyView extends Component
{
  public $fromParent, $localVariable1, localVariable2;

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

  public function render()
  {
    return view('livewire.my-view');
  }
}

我通过将 livewire 脚本@livewireScripts 放在页眉中解决了这个问题

<head>

<meta charset="utf-8" />

@livewireStyles

@livewireScripts

</head>

在我的例子中,问题来自 数据库查询和结果 collection.

这个查询(变量的意义不重要)

DB::table('progress_trackings')
        ->select('user_id')
        ->whereIn('user_id', $users->pluck('id'))
        ->where('object_id', $activity->id)
        ->where('event', $type)
        ->get()
        ->keyBy('user_id');

产生了这个输出:

Illuminate\Support\Collection {#2427
 all: [
   454 => {#2279
     +"user_id": 454,
   },
   528 => {#441
     +"user_id": 528,
   },
   531 => {#2368
     +"user_id": 531,
   },
 ],

查询是由 blade 文件中的按钮触发的。 单击按钮 2 或 3 次导致水化错误。

在 Livewire 文档中解释了数组键有时会导致问题:https://laravel-livewire.com/docs/2.x/troubleshooting

所以我尝试从数据库查询结果中创建一个普通数组。因为我只需要钥匙,所以这很有效:

DB::table('progress_trackings')
    ->select('user_id')
    ->whereIn('user_id', $users->pluck('id'))
    ->where('object_id', $activity->id)
    ->where('event', $type)
    ->get()
    ->keyBy('user_id')
    ->keys()->toArray(); // ADDED THIS

现在的结果是:

[
 454,
 528,
 531,

]

解决了水合作用错误。

除了上面其他人的建议之外,如果您有一个使用 groupBy() 的集合,也可能会发生这种情况,这可能是导致此问题的原因,

要解决此问题,请在您的组件中使用 protected $attribute 而不是 public,然后将 $attribute 传递给组件视图。

protected $attribute;

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

...........

public function render()
{
    return view('livewire.view-here',['attribute'=>$attribute]);
}

要解决此问题,请打开 vendor/livewire/livewire/src/ComponentChecksumManager.php 文件并在第 19 行 return 语句之前添加 var_dump($stringForHashing);。然后你可以看到正在被散列的数据并将其与之前的散列数据进行比较以找出差异。

完成此操作后,我能够识别出 javascript 正在重新排列的数字键,并提出了适当的修复方法。

需要注意的是,一些 json 格式化程序也会重新排列数字键,因此最好比较 json 而不格式化它或手动格式化它。

编辑: 使用 var_dump 会干扰某些页面的功能,因此将数据写入文件可能是更好的选择:

file_put_contents('/path/to/log.txt', $stringForHashing . "\n\n", FILE_APPEND);

我这样做了并且对我有用:

php artisan config:cache
php artisan config:clear

i 运行 按照命令解决了

php artisan 优化

在我的例子中,它是 API 的图像访问器,我试图在模型中为 API 获取完整的 link 图像,这是我的错误

public function getImageAttribute($value)
{ 
   return  $value ? url(Storage::url($value)) : ''; 
}

这导致我的 Livewire 遇到了损坏的数据..

我的解决方案是

 public function getImageAttribute($value)
{
    if (Str::contains(Request()->route()->getPrefix(), 'api')) {
        return  $value ? url(Storage::url($value)) : '';
    }
    return $value;
}

就我而言,我在另一个组件中有受影响的 livewire 组件。

//livewire component
<x-layouts.content-nosidebar title="false">
     <div class="verification section-padding">
     </div>
</x-layouts.content-nosidebar>

我将 livewire 组件删除到它自己的文件中,并且不再收到错误。

//livewire component
<div class="verification section-padding">
</div>

无论如何,我们的问题是一个非常大的整数,大于 javascript 可以通过 Number.MAX_SAFE_INTEGER 处理的问题。

我们在这里填写了错误报告:https://github.com/livewire/livewire/discussions/4788 (livewire 2.10.4)。

因此,当使用过大的整数时,无法解决 bug 本身。如果你想将你的值视为一个真正的整数,你现在运气不好,但也许转换为字符串可能适合你。 (and/or 在 php 侧进行计算 - 使用受保护的 属性 - 如果它在你的情况下可行)。

也就是说,我们的问题的真正原因是一个 uuid 转换为 int,因为我们没有填充 laravel 模型的 protected $keyType = 'string'; (https://laravel.com/docs/9.x/eloquent#primary-keys)!

它看起来像有一些 public 变量已使用任何 Livewire Hook 方法设置或取消设置(value-filled 或由您的代码留空)。

请检查并修复它们,这些值在生命周期挂钩方法调用期间未正确设置或取消设置,我也遇到过这个问题并已修复。

在我的例子中,在 updated 钩子方法中,我已经改变了

这个

$this->{'selectGroup.'.$value} = false;

$this->selectGroup[$value] = false;

对我来说效果很好,我希望它有意义。

我通过从 php8 降级到 php7 成功解决了这个问题。4

我的项目在生产环境中 运行 很好,但是由于某种原因,我一直在本地使用 php8

获取“尝试水合时损坏的数据”

我尝试了很多方法,但最终降级是唯一有效的方法。不确定有什么区别,但请尝试一下。

我经常使用自定义 class 属性,所以在我的情况下这是一个水合作用问题。 即使任何上游 classes 没有实现 Wireable 接口,你也会得到异常。

即使是 enum,也就是我的情况。

组件


public Notifications $notifications;

public function mount()
{
    $this->notifications = new Notifications([
        new Notification(Type::Slack);
    ]);
}

Notifications class

class Notifications implements Wireable
{
    public function toLivewire(): array
    {
         // convert to array
    }

    public function fromLivewire($value): self
    {
         // convert from array to Notifications
    }
}

Notifications class

class Notification implements Wireable
{
    public function toLivewire(): array
    {
         // convert to array
    }

    public function fromLivewire($value): self
    {
         // convert from array to Notification
    }
}

实现枚举解决了我的问题

坦率地说,我不知道 enums 可以实现接口。

enum Type: int implements Wireable
{
    case Slack = 1;
    case Teams = 2;


    public function toLivewire(): int
    {
        return $this->value;
    }

    public static function fromLivewire($value): Type
    {
        return self::from($value);
    }
}

希望对您有所帮助。