問題:reset()だけでは動作しない
error.tsxでreset()を実行しても、サーバー側のコードが再実行されず、データの再取得が行われません。
'use client'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
return (
<div>
<h2>エラーが発生しました</h2>
<button onClick={() => reset()}>
再試行
</button>
</div>
)
}
解決策:router.refresh()とstartTransitionを組み合わせる
reset()に加えてrouter.refresh()をstartTransitionでラップすることで、サーバー側のデータ取得を再実行できます。
'use client'
import { useRouter } from 'next/navigation'
import { startTransition } from 'react'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
const router = useRouter()
function handleRetry() {
startTransition(() => {
router.refresh() // サーバー側のデータを再取得
reset() // error boundaryをリセット
})
}
return (
<div>
<h2>エラーが発生しました</h2>
<button onClick={handleRetry}>
再試行
</button>
</div>
)
}
なぜこの方法で動作するのか
router.refresh()の役割
- サーバー側でルートを再実行
- データ取得ロジックとServer Componentsを再レンダリング
- 新しいデータをクライアントに送信
reset()の役割
- error boundary 内のコンポーネントを再レンダリング
startTransition()の役割
- 重い処理をノンブロッキングで実行
- クライアントサイドとサーバーサイドの両コンポーネントを同時に再レンダリング
この3つを組み合わせることで、サーバー側のデータを再取得しつつ、error boundary を適切にリセットできます。
参考