Skip to content

fix: Livewire Pagesコンポーネントのページ状態管理を一本化 - #187

Merged
128na merged 2 commits into
masterfrom
worktree-refactor-livewire-pages
Aug 14, 2026
Merged

fix: Livewire Pagesコンポーネントのページ状態管理を一本化#187
128na merged 2 commits into
masterfrom
worktree-refactor-livewire-pages

Conversation

@128na

@128na 128na commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • WithPaginationトレイトの内部状態($paginators)と、SearchActionに渡す$pageプロパティが二重管理になっており、render()冒頭のresetPage()$paginatorsしか操作しないため実質何もしていなかった。結果、検索条件(キーワード/pak/サイト)を変更しても表示ページ番号がリセットされず、フィルタ後の件数によっては空ページが表示されうるバグがあった。
  • WithPaginationを削除し、#[Url] public int $pageのみをページ状態の唯一の情報源にすることでこのバグを修正。
  • onConditionUpdate()render()を直接呼んでViewを返す設計をやめ、状態変更(ページを1に戻す)に専念させ、再描画はLivewireのライフサイクルに委譲。
  • 検索結果を#[Computed] pages()に切り出し、render()を単純化。
  • $keyword#[Validate('string|max:191')]を追加し、Blade側にエラー表示を追加。
  • Pagesコンポーネントのテストが存在しなかったため新規に6件追加(ページリセットのバグ修正を検証するテストを含む)。

E:\chore\best_practice\livewire.md のアンチパターンチェックリスト(1,2,4,5,6)に基づく対応。

Test plan

  • ./vendor/bin/pint --test
  • ./vendor/bin/phpstan analyse(level 9, 全体, エラーなし)
  • ./vendor/bin/rector process --dry-run(提案を適用済み)
  • php artisan test(63件全て通過、新規6件含む)

🤖 Generated with Claude Code

128na added 2 commits August 14, 2026 23:05
WithPaginationトレイトの内部状態($paginators)とSearchActionへ渡す$page
プロパティが二重管理になっており、render()冒頭のresetPage()は
$paginatorsのみを操作するため実際には無効化されていた。結果として
検索条件を変更しても表示ページ番号がリセットされず、フィルタ後の
結果件数によっては空ページが表示されうるバグがあった。

- WithPaginationトレイトを削除し、$pageのみを唯一の状態源にする
- onConditionUpdate()はrender()を直接呼ばず、ページ状態のリセットに専念
  (再描画はLivewireのライフサイクルに委譲)
- 検索結果を#[Computed] pages()に切り出し、render()を単純化
- $keywordに#[Validate('string|max:191')]を追加しバリデーションエラー表示を追加
- Pagesコンポーネントのテストを新規追加(既存はゼロだった)
/code-review によるセルフレビューで、直前のコミットが以下の回帰・不整合を
含んでいたことが判明したため修正する。

- WithPaginationトレイトを外した際、その内部でLaravelのPaginatorへ
  登録していたパス解決処理(Paginator::currentPathResolver)まで一緒に
  失っていた。これによりLivewireのアクション経由で再描画した後は、
  ページネーションリンクの遷移先がLivewireの内部updateエンドポイント
  (POST専用)になり、通常のリンククリック(GET)が405になっていた。
  boot()で明示的に同等の処理を肩代わりして修正。
- $pageに下限チェックが無く、?page=-1のような不正な値がそのまま
  SearchAction/paginate()に渡っていたため、max(1, $this->page)で
  クランプ。
- 追加した#[Validate('string|max:191')]が、同じ検索機能の既存API側
  バリデーション(PageSearchRequest::rules()のkeyword=>'present|max:20')
  と食い違っていたため、max:20に統一。
- 新規テストの軽微な指摘(不要なアクション呼び出しの削除、テスト名が
  謳うsitesリセットの検証漏れ)を修正。
- ページネーションリンクが内部updateエンドポイントを指さないことを
  検証する回帰テストを追加。

なお、検索条件(keyword/paks/sites)自体が`#[Url]`化されておらず、
ページネーションのプレーンリンク遷移時にURLへ乗らず消えてしまう
既存の制限は、本PRのスコープ(ページ番号の二重管理解消)外として
コード上にコメントで明記するに留めた。
@128na

128na commented Aug 14, 2026

Copy link
Copy Markdown
Owner Author

セルフレビュー結果(8観点・並列調査+検証)

自動セルフレビューで以下を検出し、対応済み。

重大: WithPagination除去でページネーションリンクが405になる回帰

use WithPagination; を外した際、その内部で行われていた Paginator::currentPathResolver の差し替え(Livewire::originalPath())まで一緒に失っていた。これにより検索・フィルタ操作を1回でも行った後は、ページネーションリンクの遷移先がLivewireの内部updateエンドポイント(POST専用)になり、通常のリンククリック(GET)が405になっていた。boot() を無効化した状態と有効化した状態を実際にテストで比較して再現・修正を確認済み(href="http://localhost/livewire-xxx/update?page=2" → 修正後は正しいページURLに戻る)。回帰防止テストを追加。

中: 負のページ番号が未クランプ

?page=-1 のような値がそのまま SearchAction/paginate() に渡っていた。max(1, $this->page) でクランプ。

中: keywordバリデーションの最大文字数が既存API側と不一致

新規追加した #[Validate('string|max:191')] が、同じ検索機能の既存API側バリデーション(PageSearchRequest::rules()keyword => 'present|max:20')と食い違っていた。max:20 に統一。

軽微: 新規テストの指摘2件

不要なアクション呼び出しの削除、テスト名が謳う sites リセットの検証漏れを解消。

対応見送り(既存の制限、スコープ外として明記)

検索条件(keyword/paks/sites)自体が #[Url] 化されておらず、ページネーションのプレーンリンク遷移時にURLへ乗らず消える既存の制限を発見。本PRのスコープ(ページ番号の二重管理解消)外のため、コード上にコメントで明記するに留めた。別issue化を検討。

🤖 Generated with Claude Code

@128na
128na merged commit 604e72e into master Aug 14, 2026
5 checks passed
@128na
128na deleted the worktree-refactor-livewire-pages branch August 14, 2026 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant