1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

react-router@v6でlazy, nested routesを実施する

Posted at

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

  1. 環境
  2. childを遅延読み込みさせる
  3. 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を分割したり実施する場合には、追加で対応が必要になります。
必要な項目としては、

  1. ChildNesteComponentsのparentにを定義する
  2. 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だして、解答をいただきたいと思っています。

Sample Repository

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?