React-Router
安装并引入
安装
npm install react-router-dom
引入
import { BrowserRouter, Route, Link } from 'react-router-dom'
基本组件
React Router 中有三类组件:
- router 组件(BrowserRouter, HashRouter)
- route matching 组件(Route,Switch)
- navigation 组件(Link,NavLink)
Router 组件
基于 React Router 的 Web 应用,其根组件应该是一个 router 组件(BrowserRouter,HashRouter)。项目中, react-router-dom
提供了两种路由,这两种路由都会创建一个 history 对象。如果我们的应用中有服务器响应 web 的请求,我们通常使用 <BrowserRouter>
组件,如果使用静态文件服务器,则我们应该使用 <HashRouter>
组件。
// 我们可以直接在 index 入口文件中引入 BrowserRouter 组件
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
holder
);
路由匹配
react-router-dom中有两个匹配路由的组件:
import { Route, Switch } from "react-router-dom";
路由匹配是通过将 Route
组件的 path 属性与当前的 location
的 pathname
进行比较来完成的。当一个 <Route>
与当前地址栏中的路径匹配了,那么它所对应的组件内容将被渲染出来;如果不匹配,则渲染 null。当一个 <Route>
没有 path 属性,那么它所对应的内容将总是会被渲染出来。
// 当 location = { pathname: '/about' }
<Route path='/about' component={About}/> // 路径匹配成功,渲染 <About/>组件
<Route path='/contact' component={Contact}/> // 路径不匹配,渲染 null
<Route component={Always}/> // 该组件没有path属性,其对应的<Always/>组件会一直渲染
我们可以在组件树的任何位置放置
多个组件在一起使用时,并不强制要求使用
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</Switch>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
{/* 如果上面的Route的路径都没有匹配上,则 <NoMatch>被渲染,我们可以在此组件中返回404 */}
<Route component={NoMatch} />
</Switch>
Route 渲染属性
component
在使用
<Route path="/user/:username" component={User} />;
function User({ match }) {
return <h1>Hello {match.params.username}!</h1>;
}
render
render 属性能使我们便捷地渲染内联组件或者是嵌套组件,我们可以给这个属性传入一个函数,当路由的路径匹配时调用。同时,render 属性也会接受所有的 Route 传入的参数。
//内联方式
<Route path="path" render={() => <div>这是内联组件写法</div>} />
//嵌套组合方式
<Route path="path" render={ props => (
<ParentComp>
<Comp {...props} />
</ParentComp>
) />
children
children 属性接收一个函数作为其值,当 Route 中有 children
属性时,不管当前的路径是否与 Route 匹配,该函数都会执行,同时,children 属性也会接收 Route 传入的所有的参数。
<Route path="path" children={ props => (
<div className={props.match? "active": ''}>
<Link to="path" />
</div>
) />
注意: 不要将 component 属性设置为一个函数,然后在其内部渲染组件。这样会导致已经存在的组件被卸载,然后重写创建一个新的组件,而不是仅仅对组件进行更新。
注意
在使用 Route 的这三个属性渲染组件时,当三个属性同时存在会有优先级的问题,正常情况下使用其中的一个属性就可以,但是如果当他们同时存在,优先渲染 children 的值,其他的不会渲染;其次,如果 component 和 render 同时存在,那么会渲染 component,而不会渲染 render 属性。
children > component > render
navigation 组件
React Router 提供了<Link>
组件用来在应用中添加跳转链接。 默认会被渲染为 a 标签。
<Link to="/">Home</Link>
// <a href='/'>Home</a>
<NavLink>
组件是一个特殊的 <Link>
组件。当它的 path
与当前 location
匹配时,可以自定义其样式来表示当前页面位置。
// location = { pathname: '/react' }
<NavLink to="/react" activeClassName="hurray">
React
</NavLink>
// <a href='/react' className='hurray'>React</a>
Redirect 组件
当页面需要重定向时,我们可以使用 <Redirect>
组件。当一个 <Redirect>
组件被渲染时,页面将被渲染到 <Redirect>
组件的 to 属性指定的位置上。
// 如果是登录状态,则跳转到 dashboard 页面,否则是公共页面
<Route exact path="/" render={() => (
loggedIn ? (
<Redirect to="/dashboard"/>
) : (
<PublicHomePage/>
)
)}/>
使用 Switch 包裹和直接使用 Route 的区别?
<Switch>
渲染第一个被 location 匹配到的并且作为子元素的<Route>
或者<Redirect>
<Switch>
是唯一的,因为它仅仅只会渲染一个路径。相比之下,不使用 <Switch>
包裹的情况下,每一个被 location 匹配的 <Route>
都将会被渲染。
<Route path='/home' component={Home}></Route>
<Route path='/home/user' component={About}></Route>
<Route component={Main}></Route>
如上述代码,如果 url 是 home,那么 <Home>
<About>
<Main>
等组件都会被渲染,因为他们的 path 都被匹配到。
然而有时我们只想选择性的渲染一个 <Route>
。如果 Url 是 /home ,但我们并不想也匹配到 /home/user (或者显示给我们的 404 页面)。我们可以利用 Switch 来处理。
<Switch>
<Route exact path='/home' component={Home}></Route>
<Route path='/home/user' component={User}></Route>
<Route path='/about' component={About}></Route>
<Route component={Main}></Route>
</Switch>
现在,如果 url 是 /home, <Switch>
将会开始寻找相匹配的 <Route>
。<Route path="/home" />
将会被匹配到,紧接着 <Switch>
会停止继续匹配并且渲染 <Home>
。同理,如果URL是/home/user,那么
exact
精确匹配的意思,如果 Route 中不添加exact
那么就会进行模糊匹配,可能会匹配多个路由,渲染多个组件
参考文章: