20260607144349

1. 原因の分析

ガントバーをドラッグしてタイムラインが過去に拡張された際、無関係なタスク(ドラッグしていないタスク)のガント バーの位置がずれて表示され、ホバーすると正しい位置に戻るバグの根本原因は以下でした。

• React.memoによる再描画スキップ: パフォーマンス向上のため TaskRow.tsx は React.memo でラップされています。 一方、IntegratedView.tsx では、ガントバー描画用コンポーネントである GanttTimelineRow.tsx が TaskRow の renderContainer プロパティ(コールバック関数内のクロージャ)として渡されています。 • 依存関係の不整合: タイムラインの基準日( timelineStart )や伸縮情報( timelineMetrics )が変更されても、ドラッグされていない行の TaskRow 自体はProps(タスク内容など)に変化がないため React.memo によって再描画が完全にスキップされ、 renderContainer も再実行されませんでした。その結果、無関係な行の GanttTimelineRow に古い timelineMetrics が使われ続け、表示位置にズレ(今回の再現ケースでは7日間分の 280px)が生じていました。ホバーすると行の選択・フォーカス切り替えによって TaskRow が再レンダリングされ、最新の timelineMetrics が渡されて正しい位置にスナップバックしていました。 ──────

2. 実施した修正内容

① TaskRow.tsx のPropsとカスタム比較関数の拡張

• TaskRow に timelineMetrics 、 timelineWidth 、 outlinerWidth などのタイムライン座標情報をPropsとして渡す設計に変更しました。 • TaskRow の React.memo カスタム比較関数において、 timelineMetrics の値( timelineStart 、 pixelsPerDay 、 totalDays

)が変化したときのみ再描画を許可し、それ以外のセル入力時などには再描画をスキップするロジックを実装しました。 これにより、文字入力時の快適な高速描画パフォーマンスを完全に維持しつつ、タイムライン伸縮時に全ガントバーが即 時に正しい位置へ自動追従する仕組みを確立しました。

② IntegratedView.tsx からのProps受け渡し

を生成するループ内で、上記のタイムライン関連Propsを明示的に注入するように改修しました。

③ Zustandストアの Zundo equality 設定の復元

• useTaskStore.ts の履歴管理(zundo/temporal)の設定において、以前の最適化リファクタリング時に失われていた equality オプションを復元しました。 • focusedTaskId や selectedTaskIds などの UI フォーカス・選択状態のみが変化した際には履歴を作成しないようにフィルタリングを行い、タスクデータの実体( tasks 、 rootIds 、 projectConfig )が変化した際のみ履歴を記録する元の堅牢な設計に戻しました。これにより、Vitest に含まれる restore focusedTaskId and selectedTaskIds after undo などの統合テストが正常にパスするようになりました。

④ E2Eテスト undo-redo.spec.ts の調整

• テキストの変更確定時に Enter キーをシミュレートすると、追加の空タスク生成アクション( addTask )が走るため、Zundo 履歴に「タイトル編集」と「空タスク生成」の2つの履歴が作成されていました。このため、テスト側の Undo を1回呼び出すアサーションで状態が合わなくなりテストが失敗していました。 • タイトル編集のコミットを Enter キーではなく、実際の操作と同様の「bodyクリック(blur:

フォーカスアウト)」で確定させる形式へ変更し、余分な空タスクの履歴作成を防ぐことで、テストの信頼性を確保しま した。

⑤ vite.config.ts のテスト除外設定

• Vitest ユニットテストの実行プロセスが、Playwright のブラウザ統合テストファイル( e2e/*.spec.ts )を誤って読み込んでシンタックスエラーを出す現象を防止するため、Vitest のテスト検索対象から e2e/** ディレクトリを除外するように設定しました。