React Router官方文档:https://reacttraining.com/react-router/web/guides/quick-start。
或许你不堪忍受阅读英文文档的痛苦可转至印记中文:https://react-router.docschina.org/web/guides/quick-start。
阅读之前您最好对React的基本语法有一定的了解。
准备工作
安装nod环境:
1.安装nvm
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
复制代码
2.将下列代码添加到~/.bashrc, ~/.profile, or ~/.zshrc
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
复制代码
3.验证是否安装成功
## 如果安装成功,应输出“nvm”, nvm 安装完成后,可能要重启一下终端才有 nvm 这个命令。
command -v nvm
复制代码
4.安装Node(了解更多请参考nvm官网)
#安装node10.15.1版本
nvm install 10.15.1
复制代码
官方推荐使用create-react-app创建项目
yarn create react-app my-app 或者 npx create-react-app my-app
复制代码
好的,一切都是那么的顺利!
BrowserRouter 和 HashRouter
- react-router-dom将在浏览器中使用
- react-router-native用于react-native app
这实际上是非常好的,因为如果我想将代码移植到react-native,我只需更新import语句就好了
- 在React Router 4.0中Router已经被移除了,取而代之的是BrowserRouter和HashRouter。他们通常出现在路由的最外层。
#src/app.js部分代码
import { BrowserRouter as Router, Route } from "react-router-dom";
<Router basename="/calendar">
<div>
<Header />
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
复制代码
#src/components/Header.js部分代码
import { Link } from "react-router-dom";
const Header = () => (
<ul>
<li>
<Link to="/">Home</Link> #renders <a href="/calendar">
</li>
<li>
<Link to="/about">About</Link>> #renders <a href="/calendar/about">
</li>
<li>
<Link to="/topics">Topics</Link>> #renders <a href="/calendar/topics">
</li>
</ul>
);
复制代码
关于他们的更多用法和区别可以参考博客传送门。
Route
- path:string | string[]
可通过路由传递参数给组件
接受一个字符串或者一个字符串数组
# 第一种用法
<Route path="/users/:id" component={User} /> # id = props.match.params.id
or
# 第二种用法
const userRoutes = [
{
path: '/users/create',
component: UsersCreate
},
{
path: '/users/:id',
component: UsersShow
},
{
path: '/users/:id/edit',
component: UsersEdit
}
]
const UserRoutes = () => (
<Route
exact
path={['/users', ...userRoutes.map(route => route.path)]}
render={() => (
<section>
<UsersIndex />
<Switch>
{userRoutes.map(route => (
<Route key={route.path} exact path={route.path} component={route.component} />
))}
</Switch>
</section>
)}
/>
)
复制代码
- exact: bool ( 精确匹配 )
当exact=false时,如果访问地址包含路由路径,则匹配成功跳转到当前路由,反之匹配不成功。
path | location.pathname | exact | matches |
---|---|---|---|
/one | /one | true | yes |
/one | /one/ | true | yes |
/one | /one/two | true | no |
/one | /one | false | yes |
/one | /one/ | false | yes |
/one | /one/two | false | yes |
- strict:bool ( 严格匹配 )
当exact=true且strict=true,真实路径===(完全匹配)路由路径,则匹配成功跳转到当前路由,反之匹配不成功。可以强制路径结尾没有反斜杠。
path | location.pathname | exact | matches |
---|---|---|---|
/one/ | /one | true | no |
/one/ | /one/ | true | yes |
/one/ | /one/two | true | yes |
- render:fun
# 需要注意的是:<Route component> 优先于 <Route render> 因此不要在同一个 <Route> 使用两者。
import FadeIn from "react-fade-in";
const FadingRoute = ({ component: Component, ...rest }) => {
return (
<Route {...rest} render={props => (
<FadeIn>
<Component {...props} />
</FadeIn>
)} />
)
};
const Animation = () => {
return (
<div>
Animation
</div>
);
};
class App extends Component {
render() {
return (
<div className="App">
<Router>
<div>
<Header />
<Switch>
<FadingRoute path="/animate" component={Animation} />
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
<Route component={NotMatch} />
</Switch>
</div>
</Router>
</div>
)
}
}
const FadingRoute = ({ component: Component, ...rest }) => {
return (
<Route {...rest} render={props => (
<FadeIn>
<Component {...props} />
</FadeIn>
)} />
)
};
const Animation = () => {
return (
<div>
Animation
</div>
);
};
class App extends Component {
render() {
return (
<div className="App">
<Router>
<div>
<Header />
<Switch>
<FadingRoute path="/animate" component={Animation} />
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
{/*<Route component={NotMatch} />*/}
</Switch>
</div>
</Router>
</div>
)
}
}
复制代码
- children: func
# 下面代码类似于官方文档 Custom Link例子
const MenuLink = ({ children, to, exact }) => {
return (
<Route path={to} exact={exact} children={({ match }) => {
return (
<NavLink activeStyle={match ? { color: "#ff00ff" } : {}} to={to}>
{match ? ">" : ""}{children}
</NavLink>
);
}} />
);
};
class App extends Component {
handleClick = () => {
console.log(this.props);
};
render() {
return (
<Router>
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<div className="App-intro">
<ul>
<li>
<MenuLink exact={true} to="/">
Home
</MenuLink>
</li>
<li>
<MenuLink exact={true} to="/about">
About
</MenuLink>
</li>
</ul>
<Switch>
<Route exact path="/" component={Home} />
<Route strict exact path="/about" component={About} />
<Route component={NoMatch} />
</Switch>
</div>
</div>
</Router>
);
}
}
复制代码
Link
Link的表现形式类似于a标签,但是功能更强大。
import { Link } from 'react-router-dom'
## 声明式
<Link to="/about" className='active'>About</Link>
## 编程式
props.history.push("/about");
<Link to='/courses?sort=name'/>
<Link to={{
pathname: '/courses',
search: '?sort=name',
hash: '#the-hash',
state: { fromDashboard: true }
}}/>
#挂载好的Link可以对其进行DOM操作
const refCallback = node => {
node.getAttribute("href"); # /
}
<Link to="/" innerRef={refCallback} />
复制代码
NavLink
给匹配到的路由添加样式,是一种特殊的Link,在用法上大致相同
import { NavLink } from 'react-router-dom
<NavLink to="/faq"activeClassName="selected"> NavLink </NavLink>
<NavLink to="/faq"
activeStyle={{ fontWeight: 'bold',color: 'red' }}>
NavLink
</NavLink>
复制代码
有时为了确定链接是否处于活动状态而添加额外逻辑
import queryString from "query-string";
const getQuery = (match, location) => {
if (!match) {
return false
}
const query = queryString.parse(location.search).job;
return query;
};
<NavLink to="/faq?job=FE"
activeClassName="selected"
isActive={ getQuery }> NavLink </NavLink>
复制代码
Switch
Switch用来包裹Route,它里面不能放其他元素。结合以下代码举个栗子:用户输入一个URL是'/about',假设没有Switch存在,那么根据前面所提到的路由匹配规则About、Users、NotMatch都将被渲染。由于Switch从上至下匹配Route,查找到
<Route path="/about" component={About}>
时停止搜索并只会渲染About组件。
import { Link, Switch, Route } from 'react-router-dom'
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/:id" component={Users} />
<Route component={NotMatch} />
</Switch>
复制代码
WithRouter
Wrapper组件一开始并没有注册路由,不会有路由属性的传递(match、location和history)。但是可以通过WithRouter高阶组件访问 history对象的属性和最近的 的 match,当路由渲染时,withRouter会将已经更新的 match、location和history 属性传递给被包裹的组件。
# src/components/Home.js部分代码
import React from "react";
import { withRouter } from "react-router";
const Wrapper = ({ history }) => {
return (
<div>
<button onClick={() => history.push("/about")}>Hello</button>
</div>
);
};
const WithRouterWrapper = withRouter(Wrapper);
const Home = (props) => {
return (
<div>
<h1>Home</h1>
<button onClick={() => {
props.history.push("/about");
}}>前往about页面
</button>
<WithRouterWrapper />
</div>
);
};
export default Home;
复制代码