From cd3f5327a01f16ba2d267350b20769278d59d7ee Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Tue, 27 May 2025 12:22:10 +0100 Subject: [PATCH 1/2] Update StateTest.php --- tests/src/Forms/StateTest.php | 74 +++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/tests/src/Forms/StateTest.php b/tests/src/Forms/StateTest.php index 70adacd4bc..35b1003085 100644 --- a/tests/src/Forms/StateTest.php +++ b/tests/src/Forms/StateTest.php @@ -486,7 +486,7 @@ test('hidden components are excluded from state dehydration except if they are m ->fill(); expect($container) - ->dehydrateState()->not()->toBe([]); + ->dehydrateState()->data->not()->toBe([]); $container = ComponentContainer::make(Livewire::make()) ->statePath('data') @@ -505,7 +505,7 @@ test('hidden components are excluded from state dehydration except if they are m ->fill(); expect($container) - ->dehydrateState()->not()->toBe([]); + ->dehydrateState()->data->not()->toBe([]); }); test('hidden components are excluded from state dehydration even if their parent component has a state path', function () { @@ -531,6 +531,74 @@ test('hidden components are excluded from state dehydration even if their parent ]); }); +test('components are not excluded from state dehydration if there is another dehydrated field with the same name', function () { + $container = ComponentContainer::make(Livewire::make()) + ->statePath('data') + ->components([ + (new Component) + ->statePath($statePath = Str::random()) + ->default(Str::random()) + ->dehydrated(false), + (new Component) + ->statePath($statePath) + ->default(Str::random()), + ]) + ->fill(); + + expect($container) + ->dehydrateState()->data->not()->toBe([]); + + $container = ComponentContainer::make(Livewire::make()) + ->statePath('data') + ->components([ + (new Component) + ->statePath($statePath = Str::random()) + ->default(Str::random()), + (new Component) + ->statePath($statePath) + ->default(Str::random()) + ->dehydrated(false), + ]) + ->fill(); + + expect($container) + ->dehydrateState()->data->not()->toBe([]); +}); + +test('hidden components are not excluded from state dehydration if there is another visible field with the same name', function () { + $container = ComponentContainer::make(Livewire::make()) + ->statePath('data') + ->components([ + (new Component) + ->statePath($statePath = Str::random()) + ->default(Str::random()) + ->hidden(), + (new Component) + ->statePath($statePath) + ->default(Str::random()), + ]) + ->fill(); + + expect($container) + ->dehydrateState()->data->not()->toBe([]); + + $container = ComponentContainer::make(Livewire::make()) + ->statePath('data') + ->components([ + (new Component) + ->statePath($statePath = Str::random()) + ->default(Str::random()), + (new Component) + ->statePath($statePath) + ->default(Str::random()) + ->hidden(), + ]) + ->fill(); + + expect($container) + ->dehydrateState()->data->not()->toBe([]); +}); + test('disabled components are excluded from state dehydration', function () { $container = ComponentContainer::make(Livewire::make()) ->statePath('data') @@ -577,7 +645,7 @@ test('disabled components are excluded from state dehydration except if they are ->fill(); expect($container) - ->dehydrateState()->not()->toBe([]); + ->dehydrateState()->data->not()->toBe([]); }); test('disabled components are excluded from state dehydration if their parent component is disabled and not marked as dehydrated', function () { From 68413f05569630e089cdfea071b3b0e9fd65d2a7 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Tue, 27 May 2025 12:40:49 +0100 Subject: [PATCH 2/2] fix --- .../src/Components/Concerns/HasState.php | 12 ++++++++++- packages/forms/src/Concerns/HasState.php | 21 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/forms/src/Components/Concerns/HasState.php b/packages/forms/src/Components/Concerns/HasState.php index 37d8bba409..04358a6b59 100644 --- a/packages/forms/src/Components/Concerns/HasState.php +++ b/packages/forms/src/Components/Concerns/HasState.php @@ -170,7 +170,17 @@ trait HasState { if (! ($isDehydrated && $this->isDehydrated())) { if ($this->hasStatePath()) { - Arr::forget($state, $this->getStatePath()); + $rootContainer = $this->getContainer(); + + while (! $rootContainer->isRoot()) { + $rootContainer = $rootContainer->getParentComponent()->getContainer(); + } + + $statePath = $this->getStatePath(); + + if (! $rootContainer->hasDehydratedComponent($statePath)) { + Arr::forget($state, $statePath); + } return; } diff --git a/packages/forms/src/Concerns/HasState.php b/packages/forms/src/Concerns/HasState.php index acf82a1255..9b670880de 100644 --- a/packages/forms/src/Concerns/HasState.php +++ b/packages/forms/src/Concerns/HasState.php @@ -78,6 +78,27 @@ trait HasState return $state; } + public function hasDehydratedComponent(string $statePath): bool + { + foreach ($this->getComponents(withHidden: true) as $component) { + if (! $component->isDehydrated()) { + continue; + } + + if ($component->hasStatePath() && ($component->getStatePath() === $statePath)) { + return true; + } + + foreach ($component->getChildComponentContainers(withHidden: true) as $container) { + if ($container->hasDehydratedComponent($statePath)) { + return true; + } + } + } + + return false; + } + /** * @param array $state * @return array