Reaksiyon yönlendirici v4 / v5 ile iç içe yollar


262

Şu anda tepki yönlendirici v4 kullanarak yuvalama yolları ile mücadele ediyorum.

En yakın örnek React-Router v4 Belgelerinde rota yapılandırmasıydı .

Uygulamamı 2 farklı bölüme ayırmak istiyorum.

Bir kullanıcı arabirimi ve bir yönetici alanı.

Ben böyle bir şey düşünüyordum:

<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} />

Ön uç, yönetici alanından farklı bir düzen ve stile sahip. Yani ön sayfada ev rotası, yaklaşık olarak çocuk rotaları olmalıdır.

/ home , Frontpage bileşenine ve / admin / home , Arka Uç bileşeninde oluşturulmalıdır.

Bazı varyasyonları denedim ama her zaman / home veya / admin / home'a ​​vurmuyorum.

Düzenle - 19.04.2017

Bu yazı şu anda çok fazla görüşe sahip olduğundan, son çözümle güncelledim. Umarım birine yardımcı olur.

Düzenle - 08.05.2017

Eski çözümler kaldırıldı

Son çözüm:

Bu şu anda kullandığım son çözüm. Bu örnek ayrıca geleneksel 404 sayfası gibi genel bir hata bileşenine sahiptir.

import React, { Component } from 'react';
import { Switch, Route, Redirect, Link } from 'react-router-dom';

const Home = () => <div><h1>Home</h1></div>;
const User = () => <div><h1>User</h1></div>;
const Error = () => <div><h1>Error</h1></div>

const Frontend = props => {
  console.log('Frontend');
  return (
    <div>
      <h2>Frontend</h2>
      <p><Link to="/">Root</Link></p>
      <p><Link to="/user">User</Link></p>
      <p><Link to="/admin">Backend</Link></p>
      <p><Link to="/the-route-is-swiggity-swoute">Swiggity swooty</Link></p>
      <Switch>
        <Route exact path='/' component={Home}/>
        <Route path='/user' component={User}/>
        <Redirect to={{
          state: { error: true }
        }} />
      </Switch>
      <footer>Bottom</footer>
    </div>
  );
}

const Backend = props => {
  console.log('Backend');
  return (
    <div>
      <h2>Backend</h2>
      <p><Link to="/admin">Root</Link></p>
      <p><Link to="/admin/user">User</Link></p>
      <p><Link to="/">Frontend</Link></p>
      <p><Link to="/admin/the-route-is-swiggity-swoute">Swiggity swooty</Link></p>
      <Switch>
        <Route exact path='/admin' component={Home}/>
        <Route path='/admin/user' component={User}/>
        <Redirect to={{
          state: { error: true }
        }} />
      </Switch>
      <footer>Bottom</footer>
    </div>
  );
}

class GlobalErrorSwitch extends Component {
  previousLocation = this.props.location

  componentWillUpdate(nextProps) {
    const { location } = this.props;

    if (nextProps.history.action !== 'POP'
      && (!location.state || !location.state.error)) {
        this.previousLocation = this.props.location
    };
  }

  render() {
    const { location } = this.props;
    const isError = !!(
      location.state &&
      location.state.error &&
      this.previousLocation !== location // not initial render
    )

    return (
      <div>
        {          
          isError
          ? <Route component={Error} />
          : <Switch location={isError ? this.previousLocation : location}>
              <Route path="/admin" component={Backend} />
              <Route path="/" component={Frontend} />
            </Switch>}
      </div>
    )
  }
}

class App extends Component {
  render() {
    return <Route component={GlobalErrorSwitch} />
  }
}

export default App;

1
Sorunuzu son cevapla güncellediğiniz için teşekkür ederiz! sadece bir öneri: belki sadece 4. listeyi ve ilkini koruyabilirsiniz, çünkü diğerleri api'nin eski sürümlerini kullanıyor ve cevaptan dikkati dağıtıyor
Giuliano Vilela 4:17

lol, bu tarihin ne biçim olduğu hakkında hiçbir fikrim yok: 08.05.2017 İnsanları karıştırmak istemiyorsanız, tarihler için evrensel ISO8601 biçimini kullanmanızı öneririm. 08 ay veya gün mü? ISO8601 = yıl.ay.gün saat.dakika.saniye (giderek daha ayrıntılı)
wesm

Güzel güncellenmiş nihai çözüm, ama bence previousLocationmantığa ihtiyacınız yok .
tudorpavel

tepki yönlendiriciyi tamamen yeniden yazmak için motivasyon nedir? İyi bir sebep olsa iyi olur
Oliver Watkins

Deklaratif yaklaşım budur. Böylece reaksiyonlarınızı reaksiyon bileşenlerini kullandığınız gibi ayarlayabilirsiniz.
datoml

Yanıtlar:


318

Reat-router-v4'te yuva yapmazsınız <Routes />. Bunun yerine, onları bir başkasının içine koyarsınız <Component />.


Örneğin

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

olmalı

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

ile

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

İşte doğrudan tepki yönlendirici belgelerinden temel bir örnek .


url'yi manuel olarak yazdığımda localhost sunucumda çalışmıyor ancak temel örnekte bağlantınızı uygulayabiliyorum. ama sizin örneğinizde var. Diğer yandan # ile manuel olarak url yazdığınızda HashRouter düzgün çalışır. Url'yi manuel olarak yazdığımda localhost sunucumda neden BrowserRouter'ın çalışmadığı hakkında bir fikriniz var mı?
himawan_r

8
Konular bileşenini bir sınıfa dönüştürebilir misiniz? ve 'match' parametresi nereden geldi? render () içinde?
user1076813

21
Eğer sadece can saçma görünüyor to="exampleTopicId"ile ${match.url}olan örtük.
greenimpala

8
Reattraining.com/react-router/web/example/route-config adresindeki her doküman için iç içe rotalarınız olabilir . Bu, dokümanlardaki konuya göre merkezi rota yapılandırmasına izin verir. Kullanılamazsa daha büyük bir projede bunun ne kadar çılgınca olacağını düşünün.
JustDave

5
Bunlar iç içe yollar değildir, hala işlevsel bir bileşeni girdi olarak alan bir Rota'nın render özelliğini kullanan tek düzeyli bir yönlendirmedir, daha dikkatli bakın, reaksiyon yönlendiricisi <4 anlamında iç içe geçme yoktur. RouteWithSubRoutes birdir - kalıp eşleşmesini kullanan yolların düzey listesi.
Lyubomir

102

react-router v6

2020 için bir güncelleme: Yakında çıkacak v6 sürümü, RouteJust Work ™ ' un iç içe geçmiş bileşenlerine sahip olacak . Bu blog gönderisindeki örnek kodlara bakın .

Orijinal soru v4 / v5 ile ilgili olsa da , v6 gemileri olduğunda doğru cevap sadece bunu yapabiliyorsanız kullanın . Şu anda alfa.


react-router v4 & v5

Rotaları iç içe yerleştirmek için, bunları Rotanın alt bileşenine yerleştirmeniz gerektiği doğrudur.

Ancak , Rotalarınızı bileşenlere ayırmak yerine daha fazla satır içi sözdizimi tercih ediyorsanız, renderyuvalamak istediğiniz Güzergahın pervanesine fonksiyonel bir bileşen sağlayabilirsiniz .

<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>

renderPervanenin değil pervane neden kullanılması gerektiğiyle ilgileniyorsanız component, bunun nedeni satır içi işlevsel bileşenin her renderde yeniden numaralandırılmasını durdurmasıdır. Daha fazla ayrıntı için belgelere bakın .

Örnekte, yuvalanmış Rotaları bir Parçaya sarar . Reaksiyon 16'dan önce <div>bunun yerine bir kap kullanabilirsiniz .


16
Şükürler olsun ki net, mantainable ve beklendiği gibi çalışan tek çözüm. Keşke tepki yönlendirici 3 iç içe yollar geri vardı.
Merunas Grincalaitis

bu mükemmel bir açısal rota-çıkış gibi görünüyor
Partha Ranjan

4
Kullanmalısın match.path, değil match.url. Birincisi genellikle Route pathpervanesinde kullanılır; ikincisi yeni bir rotaya bastığınızda (örn. Link toprop)
nbkhope

50

Bu soru gönderildiği / cevaplandığı için tepki yönlendiricisinin v4 kökten değiştiğinden bahsetmek istedim .

Artık hiçbir <Match>bileşen yok ! <Switch>yalnızca ilk eşleşmenin gerçekleştiğinden emin olmaktır. <Redirect>iyi .. başka bir rotaya yönlendiriyor. exactKısmi bir eşleşmeyi içeri almak veya hariç tutmak için kullanın veya dışarıda bırakın .

Belgelere bakın. Onlar büyük. https://reacttraining.com/react-router/

Sorunuzu cevaplamak için kullanılabileceğini umduğum bir örnek.

<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>

Umarım yardımcı olmuştur, bana bildirin. Bu örnek sorunuzu yeterince yanıtlamıyorsa, söyleyin, değiştirip değiştiremeyeceğimi anlayacağım.


Reattraining.com/react-router/web/api/Redirectexact üzerinde hiç yok . Bunun yerine yaptığımdan çok daha temiz olurdu . En azından TypeScript ile izin vermiyor. Redirect <Route exact path="/" render={() => <Redirect to="/path" />} />
Filuren

2
Yuvalanmış / alt yollar (artık) diye bir şey olmadığını doğru anladım mı? tüm rotalarda temel rotayı çoğaltmam gerekir mi? Reat-router 4 rotaların sürdürülebilir bir şekilde yapılandırılması için herhangi bir yardım sağlamaz mı?
Ville

5
@Ville şaşırdım; daha iyi bir çözüm buldunuz mu? Her yerde rota istemiyorum, gosh
punkbit

1
Bu işe yarar ancak bundle.js için webpack yapılandırmasında genel yolun "/" olarak ayarlandığından emin olun, aksi takdirde iç içe yollar sayfa yenilemede çalışmaz.
Vikrant

6

Böyle bir şey.

import React from 'react';
import {
  BrowserRouter as Router, Route, NavLink, Switch, Link
} from 'react-router-dom';

import '../assets/styles/App.css';

const Home = () =>
  <NormalNavLinks>
    <h1>HOME</h1>
  </NormalNavLinks>;
const About = () =>
  <NormalNavLinks>
    <h1>About</h1>
  </NormalNavLinks>;
const Help = () =>
  <NormalNavLinks>
    <h1>Help</h1>
  </NormalNavLinks>;

const AdminHome = () =>
  <AdminNavLinks>
    <h1>root</h1>
  </AdminNavLinks>;

const AdminAbout = () =>
  <AdminNavLinks>
    <h1>Admin about</h1>
  </AdminNavLinks>;

const AdminHelp = () =>
  <AdminNavLinks>
    <h1>Admin Help</h1>
  </AdminNavLinks>;


const AdminNavLinks = (props) => (
  <div>
    <h2>Admin Menu</h2>
    <NavLink exact to="/admin">Admin Home</NavLink>
    <NavLink to="/admin/help">Admin Help</NavLink>
    <NavLink to="/admin/about">Admin About</NavLink>
    <Link to="/">Home</Link>
    {props.children}
  </div>
);

const NormalNavLinks = (props) => (
  <div>
    <h2>Normal Menu</h2>
    <NavLink exact to="/">Home</NavLink>
    <NavLink to="/help">Help</NavLink>
    <NavLink to="/about">About</NavLink>
    <Link to="/admin">Admin</Link>
    {props.children}
  </div>
);

const App = () => (
  <Router>
    <div>
      <Switch>
        <Route exact path="/" component={Home}/>
        <Route path="/help" component={Help}/>
        <Route path="/about" component={About}/>

        <Route exact path="/admin" component={AdminHome}/>
        <Route path="/admin/help" component={AdminHelp}/>
        <Route path="/admin/about" component={AdminAbout}/>
      </Switch>

    </div>
  </Router>
);


export default App;


6

Ben Switchkök yolu daha önce iç içe rota ile sarma ve tanımlayarak iç içe yollar tanımlamayı başardı .

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

Referans: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Switch.md


Siparişin yeniden düzenlenmesi, bunun herhangi bir yan etkisi olup olmayacağını bilmememe rağmen sorunumu düzeltti. ama şimdilik çalışıyor .. teşekkürler :)
Anbu369

2

Routes.js gibi bir şey deneyebilirsiniz

import React, { Component } from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom';
import FrontPage from './FrontPage';
import Dashboard from './Dashboard';
import AboutPage from './AboutPage';
import Backend from './Backend';
import Homepage from './Homepage';
import UserPage from './UserPage';
class Routes extends Component {
    render() {
        return (
            <div>
                <Route exact path="/" component={FrontPage} />
                <Route exact path="/home" component={Homepage} />
                <Route exact path="/about" component={AboutPage} />
                <Route exact path="/admin" component={Backend} />
                <Route exact path="/admin/home" component={Dashboard} />
                <Route exact path="/users" component={UserPage} />    
            </div>
        )
    }
}

export default Routes

App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import { BrowserRouter as Router, Route } from 'react-router-dom'
import Routes from './Routes';

class App extends Component {
  render() {
    return (
      <div className="App">
      <Router>
        <Routes/>
      </Router>
      </div>
    );
  }
}

export default App;

Aynı şeyi buradan da başarabileceğinizi düşünüyorum.


iyi bir nokta! Java Spring önyükleme uygulaması geliştirildikten sonra React ile başladığımda aynı şekilde düşündüm. değiştireceğim tek şey Routes.js'de 'div' ile 'Switch'. Ve tbh sen App.js tüm yolları tanımlayabilir ama (create-tepki-app) örneğin index.js dosyasında dışında sar
Reborn

Evet haklısın! Bu şekilde uyguladım, bu yüzden bu yöntemden bahsediyorum.
Aniruddh Agarwal

-6
interface IDefaultLayoutProps {
    children: React.ReactNode
}

const DefaultLayout: React.SFC<IDefaultLayoutProps> = ({children}) => {
    return (
        <div className="DefaultLayout">
            {children}
        </div>
    );
}


const LayoutRoute: React.SFC<IDefaultLayoutRouteProps & RouteProps> = ({component: Component, layout: Layout, ...rest}) => {
const handleRender = (matchProps: RouteComponentProps<{}, StaticContext>) => (
        <Layout>
            <Component {...matchProps} />
        </Layout>
    );

    return (
        <Route {...rest} render={handleRender}/>
    );
}

const ScreenRouter = () => (
    <BrowserRouter>
        <div>
            <Link to="/">Home</Link>
            <Link to="/counter">Counter</Link>
            <Switch>
                <LayoutRoute path="/" exact={true} layout={DefaultLayout} component={HomeScreen} />
                <LayoutRoute path="/counter" layout={DashboardLayout} component={CounterScreen} />
            </Switch>
        </div>
    </BrowserRouter>
);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.