在React-router学习笔记 react-router基本使用中,我做了精确的路由匹配,但是实际上,我们在进行路由匹配的时候,一般是会进行多级路由的匹配,所以这里说说如何进行多级路由的匹配
在使用react-router-dom的Link的时候,我们需要使用to来指定路由,而Route用来显示路由对应得内容,默认情况下,Route 会进行路由的模糊匹配
<Route path="/topics" component={Topics}></Route>
上面的这个Route,在路由为/topics时可以显示,在路由为/topics/str时也可以显示(str随机的字符串),所以我们可以利用这个特点,让该Route对应的组件在显示多级路由内容时也可以显示
简单的代码如下
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router,Route,Link } from 'react-router-dom'
class AppRouter extends React.Component{
render(){
return(
<Router>
<RouterLink />
<RouterShow />
</Router>
)
}
}
class RouterLink extends React.Component{
render(){
return(
<>
<li>
<Link to="/">HOME</Link>
</li>
<li>
<Link to="/about">ABOUT</Link>
</li>
<li>
<Link to="/topics">TOPICS</Link>
</li>
</>
)
}
}
class RouterShow extends React.Component{
render(){
return(
<>
<Route exact path="/" component={Home} />
<Route exact path="/about" component={About} />
<Route path="/topics" component={Topics} />
</>
)
}
}
class Home extends React.Component{
render(){
return(
<div>
<h1>this is Home page</h1>
</div>
)
}
}
class About extends React.Component{
render(){
return (
<div>
<h1>this is About page</h1>
</div>
)
}
}
class Topics extends React.Component{
render(){
return (
<div>
<h1>this is Topics page</h1>
<hr/>
<div>
<li>
<Link to="/topics/topic1">topic1</Link>
</li>
<li>
<Link to="/topics/topic2">topic2</Link>
</li>
<li>
<Link to="/topics/topic3">topic3</Link>
</li>
</div>
<hr/>
<div>
<Route path="/topics/topic1" component={Topic1}/>
<Route path="/topics/topic2" component={Topic2} />
<Route path="/topics/topic3" component={Topic3}/>
</div>
</div>
)
}
}
class Topic1 extends React.Component{
render(){
return <p>here is topic1</p>
}
}
class Topic2 extends React.Component{
render(){
return <p>here is topic2</p>
}
}
class Topic3 extends React.Component{
render(){
return <p>here is topic3</p>
}
}
ReactDOM.render(<AppRouter />, document.getElementById('root'))
上面的代码固然实现了效果,但是显然,很多内容显得过于冗余了,三个子Topic组件看起来很是类似,只是显示的内容有点不一样,我们是不是可以尝试使用一个组件,然后在父组件传值进来显示呢,答案当然是可以的,我们可以通过props来获取父组件的内容,也可以通过props来获取url的内容
我们将Topic1组件修改成下面这样子,打印出props
class Topic1 extends React.Component{
constructor(props){
super(props);
console.log(props)
}
render(){
return <p>here is topic1</p>
}
}
观察打印内容,可以看到props.match中就有相应的路由,我们可以通过获取对应的url,来修改子组件的内容(这里url和path是一样的,使用path的理由会在下面提及)
但是这样子的话,我们还需要将path对应的字符串的前缀路由去掉,才能匹配到我们真正想要的topic1,我们要想个办法来更好地获取我们要的内容
在Route中,我们可以通过:的写法,来将路由对应的内容,反映到params的属性上,我们修改三个Route
<Route path="/topics/:topicName" component={Topic1}/>
<Route path="/topics/:topicName" component={Topic2} />
<Route path="/topics/:topicName" component={Topic3}/>
重新看以下控制台的打印内容
我们发现,params已经不再是一个空对象了,而且里面的属性的key,正是我们写在:后面的内容,而key对应的内容,正是子路由的内容
同时这里我们也看到了path和url的不同了,url是真实的路由,而path是我们写在Route上的path属性的值。
回归正题,既然我们可以通过这种方式来获得想应的内容,那我们就可以对我们写的代码进行优化了,将三个子Topic组件合成一个,获取props.match的内容来修改子组件的内容,三个Route也可以合成一个了
<Route path="/topics/:topicName" component={Topic}/>
class Topic extends React.Component{
constructor(props){
super(props);
console.log(props)
}
render(){
return <p>here is {this.props.match.params.topicName}</p>
}
}
这部分优化完后,我们看看别的部分,我们发现,每次写子组件时,都要记住父组件对应的路由,写在每个Link和Route里面,万一路由进行修改,那相关的子组件也要修改,很不利于维护,所以我们要采用别的方式
其实我们要做的和上面是一样的,通过props的内容来进行路由跳转,我们将props的内容写入Link和Route中,要注意的是在Link中写入path,在Route中写入url,实际上文档中也这么写了
所以修改代码如下
class Topics extends React.Component{
render(){
return (
<div>
<h1>this is Topics page</h1>
<hr/>
<div>
<li>
<Link to={`${this.props.match.path}/topic1`}>topic1</Link>
</li>
<li>
<Link to={`${this.props.match.path}/topic2`}>topic2</Link>
</li>
<li>
<Link to={`${this.props.match.path}/topic3`}>topic3</Link>
</li>
</div>
<hr/>
<div>
<Route path={`${this.props.match.url}/:topicName`} component={Topic}/>
</div>
</div>
)
}
}
至此基本完成多级路由匹配的优化