我尝试将大部分路线渲染为AppShell
组件的子组件,其中包含导航栏。但我想将我的404路由渲染为一个未包含在AppShell
中的独立组件。
<Router>
<Route component={AppShell}>
<Route path="/about" component={About} />
<Route path="/" component={Home} />
</Route>
<Route path="*" component={NotFound} />
</Router>
一切都按预期运作:
/
呈现<AppShell><Home /></AppShell>
/about
呈现<AppShell><About /></AppShell>
/blah
呈现<NotFound />
现在我正在做这个,但问题是呈现AppShell
(没有孩子,但仍然是导航栏):
const Routes = () => (
<div>
<AppShell>
<Match exactly pattern="/" component={Home} />
<Match pattern="/about" component={About} />
</AppShell>
<Miss component={NotFound} />
</div>
)
有了这个:
/
呈现<div><AppShell><Home /></AppShell></div>
(好)/about
呈现<div><AppShell><About /></AppShell></div>
(好)/blah
呈现<div><AppShell /><NotFound /></div>
(问题 - 我想摆脱<AppShell />
) pattern
:const InAppShell = (): React.Element<any> => (
<AppShell>
<Match pattern="/about" component={About} />
<Match pattern="/contact" component={Contact} />
</AppShell>
)
const App = (): React.Element<any> => (
<div>
<Match pattern={['/contact', '/about']} component={InAppShell} />
<Miss component={NotFound} />
</div>
)
pattern
的数组exactly
可以使用根路由:但是我必须在pattern
数组中放置所有可能的子路径 ...
const InAppShell = (): React.Element<any> => (
<AppShell>
<Match exactly pattern="/" component={Home} />
<Match pattern="/about" component={About} />
</AppShell>
)
const App = (): React.Element<any> => (
<div>
<Match exactly pattern={["/", "/about"]} component={InAppShell} />
<Miss component={NotFound} />
</div>
)
但是在一个有很多路线的大型应用程序中,这将非常难以理解。
Match
单独/
:const InAppShell = (): React.Element<any> => (
<AppShell>
<Match exactly pattern="/" component={Home} />
<Match pattern="/about" component={About} />
<Match pattern="/contact" component={Contact} />
</AppShell>
)
const App = (): React.Element<any> => (
<div>
<Match exactly pattern="/" component={InAppShell} />
<Match pattern={["/about", "/contact"]} component={InAppShell} />
<Miss component={NotFound} />
</div>
)
但每次我过渡到回家路线时,这都会重新安装<AppShell>
。
这里似乎不是一个理想的解决方案;我认为这是v4需要解决的基本API设计挑战。
如果我能做<Match exactlyPattern="/" pattern={["/about", "/contact"]} component={InAppShell} />
...
答案 0 :(得分:5)
我一直在解决同样的问题 - 我想你可能想要这样的东西,'全球404':
https://codepen.io/pshrmn/pen/KWeVrQ
const {
HashRouter,
Route,
Switch,
Link,
Redirect
} = ReactRouterDOM
const Global404 = () => (
<div>
<h1>Oh, no!</h1>
<p>You weren't supposed to see this... it was meant to be a surprise!</p>
</div>
)
const Home = () => (
<div>
The links to "How?" and "Random" have no matching routes, so if you click on either of them, you will get a "global" 404 page.
</div>
)
const Question = ({ q }) => (
<div>
<div>Question: {q}</div>
<div>Answer: I have no idea</div>
</div>
)
const Who = () => <Question q={"Who?"}/>
const What = () => <Question q={"What?"}/>
const Where = () => <Question q={"Where?"}/>
const When = () => <Question q={"When?"}/>
const Why = () => <Question q={"Why?"}/>
const RedirectAs404 = ({ location }) =>
<Redirect to={Object.assign({}, location, { state: { is404: true }})}/>
const Nav = () => (
<nav>
<ul>
<li><Link to='/'>Home</Link></li>
<li><Link to='/faq/who'>Who?</Link></li>
<li><Link to='/faq/what'>What?</Link></li>
<li><Link to='/faq/where'>Where?</Link></li>
<li><Link to='/faq/when'>When?</Link></li>
<li><Link to='/faq/why'>Why?</Link></li>
<li><Link to='/faq/how'>How?</Link></li>
<li><Link to='/random'>Random</Link></li>
</ul>
</nav>
)
const App = () => (
<Switch>
<Route exact path='/' component={Home}/>
<Route path='/faq' component={FAQ}/>
<Route component={RedirectAs404}/>
</Switch>
)
const FAQ = () => (
<div>
<h1>Frequently Asked Questions</h1>
<Switch>
<Route path='/faq/who' component={Who}/>
<Route path='/faq/what' component={What}/>
<Route path='/faq/where' component={Where}/>
<Route path='/faq/when' component={When}/>
<Route path='/faq/why' component={Why}/>
<Route component={RedirectAs404}/>
</Switch>
</div>
)
ReactDOM.render((
<HashRouter>
<div>
<Nav />
<Route render={({ location }) => (
location.state && location.state.is404
? <Global404 />
: <App />
)}/>
</div>
</HashRouter>
), document.getElementById('root'))
答案 1 :(得分:1)
关于v4,我最不喜欢的事情是,应该组合在一起的匹配和未命中可以放在组件树中的不同级别上。这导致像你这样的情况,你有一个组件,只应该为某些匹配渲染,但多级匹配结构允许你在其中嵌套匹配。
您应该将<AppShell>
渲染为需要它的每个组件的容器。
const Home = (props) => (
<AppShell>
<div>
<h1>Home</h1>
</div>
</AppShell>
)
const About = (props) => (
<AppShell>
<div>
<h1>About</h1>
</div>
</AppShell>
)
const App = () => (
<div>
<Match exactly pattern='/' component={Home} />
<Match pattern="/about" component={About} />
<Miss component={NotFound} />
</div>
)
您还可以使用<MatchRoutes>
组件。我更喜欢这个,因为它强迫相关路线组合在一起。
const App = () => (
<MatchRoutes missComponent={NotFound} routes={[
{ pattern: '/', exact: true, component: Home },
{ pattern: '/about', component: About }
]} />
)
答案 2 :(得分:0)
我提出了一个自定义<Match>
组件,这是一种可能的解决方案。尽管如此,它还远远不是一种商定的标准方式。
https://gist.github.com/jedwards1211/15140b65fbeafcbc14dec728fee16f59
用法类似于
const InAppShell = (): React.Element<any> => (
<AppShell>
<Match exactPattern="/" component={Home} />
<Match pattern="/about" component={About} />
<Match pattern="/contact" component={Contact} />
</AppShell>
)
const App = (): React.Element<any> => (
<div>
<Match exactPattern="/" patterns={["/about", "/contact"]} register={false} component={InAppShell} />
<Match notExactPattern="/" notPatterns={["/about", "/contact"]} register={false} component={NotFound} />
</div>
)