جاوااسکریپت - مسیرهای تو در تو با ریاکت روتِر نسخه ۴/۵


من در حال حاضر با مسیریابی تودرتو در ریاکت روتِر نسخه ۴ مشکل دارم.

نزدیکترین مثال، پیکربندی مسیر در مستندات React-Router نسخه ۴ بود.

من میخواهم برنامهام را به دو قسمت مختلف تقسیم کنم.

یک رابط کاربری و یک بخش مدیریت.

من داشتم به چیزی شبیه به این فکر میکردم:

<Match pattern="/" component={Frontpage}>
  <Match pattern="/home" component={HomePage} />
  <Match pattern="/about" component={AboutPage} />
</Match>
<Match pattern="/admin" component={Backend}>
  <Match pattern="/home" component={Dashboard} />
  <Match pattern="/users" component={UserPage} />
</Match>
<Miss component={NotFoundPage} />

نمای جلویی دارای طرح و سبک متفاوتی نسبت به بخش مدیریت است. بنابراین در صفحه اصلی، مسیرهای home، about و غیره باید مسیرهای فرزند باشند.

مسیر /home باید در کامپوننت Frontpage نمایش داده شود و مسیر /admin/home باید درون کامپوننت Backend نمایش داده شود.

من برخی تغییرات دیگر را امتحان کردم اما همیشه به این نتیجه رسیدم که /home یا /admin/home را ندیدهام.

پاسخ شماره ۱

در react-router-v4 شما <Routes /> را تو در تو نمیکنید. در عوض، آنها را داخل یک <Component /> دیگر قرار میدهید.

برای مثال

<Route path='/topics' component={Topics}>
  <Route path='/topics/:topicId' component={Topic} />
</Route>

باید شود

<Route path='/topics' component={Topics} />

با

const Topics = ({ match }) => (
  <div>
    <h2>Topics</h2>
    <Link to={`${match.url}/exampleTopicId`}>
      Example topic
    </Link>
    <Route path={`${match.path}/:topicId`} component={Topic}/>
  </div>
) 

در اینجا یک مثال پایهای مستقیم از مستندات react-router آورده شده است.

پاسخ شماره ۲

ریاکت-روتر v6

بهروزرسانی برای ۲۰۲۲ - نسخه ۶ شامل کامپوننتهای Route تو در تو است که بدون مشکل کار میکنند™.

این سوال در مورد v4/v5 است، اما بهترین پاسخ اکنون این است که اگر میتوانید، فقط از v6 استفاده کنید!

مثال کد را در این پست وبلاگ ببینید. با این حال، اگر هنوز نمیتوانید ارتقا دهید...

ریداکتور روتر v4 و v5

درست است که برای تو در تو قرار دادن مسیرها، باید آنها را در کامپوننت فرزند مسیر قرار دهید.

با این حال، اگر ترجیح میدهید از نحو خطیتری استفاده کنید به جای اینکه مسیرهای خود را در اجزاء مختلف تقسیم کنید، میتوانید یک جزء تابعی را به ویژگی render مسیری که میخواهید در زیر آن تو در تو شود، ارائه دهید.

<BrowserRouter>

  <Route path="/" component={Frontpage} exact />
  <Route path="/home" component={HomePage} />
  <Route path="/about" component={AboutPage} />

  <Route
    path="/admin"
    render={({ match: { url } }) => (
      <>
        <Route path={`${url}/`} component={Backend} exact />
        <Route path={`${url}/home`} component={Dashboard} />
        <Route path={`${url}/users`} component={UserPage} />
      </>
    )}
  />

</BrowserRouter>

اگر علاقهمند هستید که بدانید چرا باید از ویژگی render استفاده شود و نه ویژگی component، دلیل آن این است که این کار مانع از این میشود که کامپوننت تابعی نوشتاری در هر بار رندر دوباره نصب شود. برای جزئیات بیشتر به مستندات مراجعه کنید.

توجه داشته باشید که مثال مسیرهای تو در تو را در یک Fragment قرار میدهد. قبل از React 16، میتوانید به جای آن از یک ظرف <div> استفاده کنید.

پاسخ شماره ۳

فقط میخواستم ذکر کنم که react-router v4 بهطور چشمگیری تغییر کرده است از زمان انتشار/پاسخدهی به این سؤال.

دیگر هیچ کامپوننت <Match> وجود ندارد! <Switch> برای اطمینان از این است که تنها اولین تطبیق رندر شود. <Redirect> خب .. به مسیر دیگری هدایت میکند. از exact استفاده کنید یا آن را رها کنید تا تطبیق جزئی را شامل یا کنار بگذارید.

به مستندات نگاه کنید. آنها عالی هستند. https://reacttraining.com/react-router/

در اینجا یک مثال است که امیدوارم قابل استفاده برای پاسخ به سوال شما باشد.

<Router>
  <div>
    <Redirect exact from='/' to='/front'/>
    <Route path="/" render={() => {
      return (
        <div>
          <h2>Home menu</h2>
          <Link to="/front">front</Link>
          <Link to="/back">back</Link>
        </div>
      );
    }} />          
    <Route path="/front" render={() => {
      return (
        <div>
        <h2>front menu</h2>
        <Link to="/front/help">help</Link>
        <Link to="/front/about">about</Link>
        </div>
      );
    }} />
    <Route exact path="/front/help" render={() => {
      return <h2>front help</h2>;
    }} />
    <Route exact path="/front/about" render={() => {
      return <h2>front about</h2>;
    }} />
    <Route path="/back" render={() => {
      return (
        <div>
        <h2>back menu</h2>
        <Link to="/back/help">help</Link>
        <Link to="/back/about">about</Link>
        </div>
      );
    }} />
    <Route exact path="/back/help" render={() => {
      return <h2>back help</h2>;
    }} />
    <Route exact path="/back/about" render={() => {
      return <h2>back about</h2>;
    }} />
  </div>
</Router>

امیدوارم مفید بوده باشد، به من اطلاع دهید. اگر این مثال به اندازه کافی به سوال شما پاسخ نمیدهد، به من بگویید و من میبینم آیا میتوانم آن را اصلاح کنم.

پاسخ شماره ۴

من در تعریف مسیرهای تو در تو با استفاده از Switch موفق شدم و مسیر تو در تو را قبل از مسیر اصلی تعریف کردم.

<BrowserRouter>
  <Switch>
    <Route path="/staffs/:id/edit" component={StaffEdit} />
    <Route path="/staffs/:id" component={StaffShow} />
    <Route path="/staffs" component={StaffIndex} />
  </Switch>
</BrowserRouter>

مرجع: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Switch.md

پاسخ شماره ۵

استفاده از هوکها

آخرین بهروزرسانی با هوکها این است که از useRouteMatch استفاده کنید.

کامپوننت اصلی مسیریابی

export default function NestingExample() {
  return (
    <Router>
      <Switch>
       <Route path="/topics">
         <Topics />
       </Route>
     </Switch>
    </Router>
  );
}

کامپوننت فرزند

function Topics() {
  // The `path` lets us build <Route> paths 
  // while the `url` lets us build relative links.

  let { path, url } = useRouteMatch();

  return (
    <div>
      <h2>Topics</h2>
      <h5>
        <Link to={`${url}/otherpath`}>/topics/otherpath/</Link>
      </h5>
      <ul>
        <li>
          <Link to={`${url}/topic1`}>/topics/topic1/</Link>
        </li>
        <li>
          <Link to={`${url}/topic2`}>/topics/topic2</Link>
        </li>
      </ul>

      // You can then use nested routing inside the child itself
      <Switch>
        <Route exact path={path}>
          <h3>Please select a topic.</h3>
        </Route>
        <Route path={`${path}/:topicId`}>
          <Topic />
        </Route>
        <Route path={`${path}/otherpath`>
          <OtherPath/>
        </Route>
      </Switch>
    </div>
  );
}