react-router@v6でlazy,nested-routesを実現する
TL;DR
React Lazyを利用して、
child-component
でnestedする場合のpathには、path="child-nested/*"
を実施、componentをparentに持つ。
child-component
をlazyで利用する場合は、lazyの中に入れればOK。
table of contents
- 環境
- childを遅延読み込みさせる
- nested-childを遅延読み込みさせる
1. 環境
package name | version |
---|---|
vite | 3.0.4 |
react | 18.2.0 |
react-dom | 18.2.0 |
react-router | 6.3.0 |
react-router-dom | 6.3.0 |
App.tsx
export function App() {
return (
<div>
<BrowserRouter>
<nav>
<ul>
<li><Link to="/">root</Link></li>
<li><Link to="/child">child</Link></li>
<li><Link to="/child-nested">child nested root</Link></li>
<li><Link to="/child-nested/a">child nested a</Link></li>
<li><Link to="/child-nested/b">child nested b</Link></li>
</ul>
</nav>
<main>
<Route path="/" element={<p>root main</p>} />
</main>
</BrowserRouter>
</div>
)
}
error-bondary.tsx
import { Component, ErrorInfo, ReactNode } from "react"
interface ErrorBoundaryState {
hasError: boolean
}
interface ErrorBoundaryProps {
children: ReactNode
}
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: unknown) {
return { hasError: true };
}
override componentDidCatch(error: unknown, errorInfo: ErrorInfo) {
console.log(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
1. childを遅延読み込みさせる
childの遅延読み込みは、React.lazyを利用して、componentの呼び出しを実施するだけで遅延読み込みができます。
child-page.tsx
export function ChildPage() {
return (
<p>child page</p>
)
}
export default ChildPage
App.tsx
// [Start]追記
const ChildPage = lazy(() => import('./child-page'))
// [End]追記
export function App() {
return (
<div>
<BrowserRouter>
<nav>
<ul>
<li><Link to="/">root</Link></li>
<li><Link to="/child">child</Link></li>
<li><Link to="/child-nested">child nested root</Link></li>
<li><Link to="/child-nested/a">child nested a</Link></li>
<li><Link to="/child-nested/b">child nested b</Link></li>
</ul>
</nav>
<main>
<Route path="/" element={<p>root main</p>} />
// [Start]追記
<Route path="child" element={
<ErrorBoundary>
<Suspense fallback={<p>Loading...</p>}>
<ChildPage />
</Suspense>
</ErrorBoundary>
} />
// [End]追記
</main>
</BrowserRouter>
</div>
)
}
React.lazyを利用しているため、を利用して読み込み中の表示を実施します。
また、例外処理を拾わないため、でError時間の処理を実施します。
2. nested-childを遅延読み込みさせる
child-componentがroutingを保持していない場合には、上記の対応だけでいいのですがroutingを分割したり実施する場合には、追加で対応が必要になります。
必要な項目としては、
- ChildNesteComponentsのparentにを定義する
- lazyで読み込むComopnentのpathは、
FOO/*
の形式にする
child-nested-page.tsx
import { Route, Routes } from "react-router-dom"
export function ChildNestedPage() {
return (
<Routes>
<Route index element={<div>child nested root</div>} />
<Route path="a" element={<div>child nested page a</div>} />
<Route path="b" element={<div>child nested page b</div>} />
</Routes>
)
}
export default ChildNestedPage
App.tsx
const ChildPage = lazy(() => import("./child-page"))
// [Start]追記
const ChildNestedPage = lazy(() => import("./child-nested-page"))
// [End]追記
function App() {
return (
<div className="App">
<BrowserRouter>
<nav>
<ul>
<li><Link to="/">root</Link></li>
<li><Link to="/child">child</Link></li>
<li><Link to="/child-nested">child nested root</Link></li>
<li><Link to="/child-nested/a">child nested a</Link></li>
<li><Link to="/child-nested/b">child nested b</Link></li>
</ul>
</nav>
<Routes>
<Route path="" element={<div>main</div>} />
// [Start]追記
/**
* path="child-nested"の形だとroutingが読み込まれません
* path="child-nested/*"にすると正常に読み込みがされる
**/
<Route path="child-nested/*" element={
<ErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<ChildNestedPage />
</Suspense>
</ErrorBoundary>
} />
// [End]追記
<Route path="child" element={
<ErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<ChildPage />
</Suspense>
</ErrorBoundary>
} />
</Routes>
</BrowserRouter>
</div>
)
}
export default App
Sampleも空になっているので、気が向いたら本家にPRだして、解答をいただきたいと思っています。