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;
複製程式碼