【一起來學React】React-Router學習
在web下我們一般都使用react-router-dom,相比於react-router多了一些DOM操作方法,你可以嘗試單獨安裝react-router-dom,看依賴包裡面是不是會包含了react-router,本文就記錄下react-router-dom一些筆記(文章中api示例只給出了常用,詳細api請檢視官方文件)長篇文章警告!
安裝
npm install react-router-dom
基本使用
import React from 'react';
import {BrowserRouter, Route, Switch} from 'react-router-dom' ;
const Router = () => {
return (
<BrowserRouter>
<Switch>
<Route path='/' exact component={AsyncHome}/>
<Route path='/hot' exact component={AsyncHot}/>
</Switch>
</BrowserRouter>
)
}
export default Router
// 然後在App.js
import Router from './router';
const App = () => {
render(){
return (
<React.Fragment>
<Header/>
{router}
</React.Fragment>
)
}
}
export default App
//最後在inde中引用App即可
基本元件
React-Router
中有三種類型的元件:路由器元件,路由匹配元件和導航元件
路由器元件
react-router-dom
提供<BrowserRouter>
和<HashRouter>
路由器
<BrowserRouter>
:原理是使用HTML5 history API,內容隨著url動態改變<HashRouter>
:有是根據hash值對路由進行控制的(會有#)
舉個例子:
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
路由匹配元件
有兩個路由匹配元件:<Route>
和<Switch>
-
<Route>
:Route是路由的一個原材料,它是控制路徑對應顯示的元件。經常用的是exact、path以及component屬性
exact:控制匹配到/路徑時不會再繼續向下匹
path:路由的路徑
component:顯示元件 -
<Switch>
:Switch常常會用來包裹Route,它裡面不能放其他元素,用來只顯示一個路由。
舉個例子:
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</Switch>
API:
名稱 | 示例 | 屬性 | 作用 |
---|---|---|---|
path | /users/:id | string | 定義路徑 |
exact | exact path="/one" | bool | 嚴格匹配 |
導航元件
<Link>
和<NavLink>
一般在元件內跳轉連結用的
<Link>
:<Link to="/home">
to可以接收一個string和object<NavLink>
:可以為當前選中的路由設定類名、樣式以及回撥函式等
舉個例子:
<Link
to={{
pathname: "/courses",
search: "?sort=name",
hash: "#the-hash",
state: { fromDashboard: true }
}}
/>
<NavLink
to="/faq"
activeStyle={{
fontWeight: "bold",
color: "red"
}}
>
FAQs
</NavLink>
API:
<Link>
名稱 | 示例 | 屬性 | 作用 |
---|---|---|---|
to | to="/home" | string | 跳轉路徑 |
exact | exact to="/one" | bool | 嚴格匹配 |
<NavLink>
名稱 | 示例 | 屬性 | 作用 |
---|---|---|---|
to | to="/home" | string/object | 跳轉路徑 |
exact | exact to="/one" | bool | 嚴格匹配 |
activeClassName | activeClassName=‘active’ | string | 當前路徑選中狀態的類名 |
程式碼拆分
其實就是按需載入,不管是官方還是開發者,都有給出自己的方式,這裡給出官方的示例程式碼,在我看來還是挺簡單的!
create-react-app
npm install @babel/plugin-syntax-dynamic-import
//router>index.js
import Loadable from "react-loadable";
import Loading from "./Loading";
const Home = Loadable({
loader: () => import("./home"),
loading: Loading//必須配置loading元件,不然報錯
});
const Router = () => {
return (
<BrowserRouter>
<Switch>
<Route path='/' exact component={Home}/>
</Switch>
</BrowserRouter>
)
}
export default Router
更多按需載入的方法請參考:https://segmentfault.com/a/1190000009539836
重定向
使用<Redirect>
可以重定向路徑
import { Route, Redirect } from 'react-router'
//to是string的時候
<Route exact path="/" render={() => (
loggedIn ? (
<Redirect to="/dashboard"/>
) : (
<PublicHomePage/>
)
)}/>
//進入首頁,判斷是否已登陸,如果登陸重定向到使用者面板
//當to是object的時候
<Redirect
to={{
pathname: "/login",
search: "?utm=your+face",
state: { referrer: currentLocation }
}}
/>
match
match是在使用router之後被放入props中的一個屬性(/home/:id)
match物件包含以下屬性:
- params - (物件)從與路徑的動態段對應的URL解析的鍵/值對
- isExact- (boolean)是否是嚴格模式
- path - (字串)用於匹配的路徑模式。
- url - (字串)URL的匹配部分。
withRouter
使用過vue-router的同學可能剛開始會很奇怪,為什麼react-router沒有直接在元件中js跳轉路由的方法,比如this.$router.push
withRouter:是一個可以讓你訪問history
物件的屬性和最近<Route>
的match
的高階元件
利用withRouter達到路由js跳轉
import React from "react";
import {withRouter } from 'react-router-dom';
class TLogin extends React.Component {
handleJump(){//在方法內呼叫
this.props.history.push('/home')
}
render() {
//dosomething
}
}
const Login = withRouter(TLogin)
export default Login;
//使用react-redux的時候
onst Login = withRouter(connect(...)(TLogin))
export default Login;
路由巢狀
v4中不支援以前這種寫法
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox}>
<Route path="messages/:id" component={Message} />
</Route>
</Route>
v4中子路由,應寫在對應的元件內部中,當然你可以用react-router-config
物件的方式配置巢狀,和vue-router一樣的。
npm install --save react-router-config
//app.js
import {renderRoutes} from 'react-router-config';
import Router from './router';
const App = () => {
render(){
return (
<React.Fragment>
<Header/>
{renderRoutes(Router)}
</React.Fragment>
)
}
}
export default App
//./router
export const Router = [
{
component: home,
path:'/',
},{
component:parent,
path:'/parent',
routes: [
{
path: "/parent/:id",
component: Child,
routes: [
{
path: "/parent/:id/grand-child",
component: GrandChild
}
]
}
]
}
];
非同步載入元件
1.新建AsyncComponents元件
import React, {Component} from 'react';
export default function asyncComponents(importComponent) {
class AsyncComponent extends Component {
constructor(props) {
super(props);
this.state = {
component: null,
}
}
async componentDidMount() {//非同步
const {default: component} = await importComponent();
this.setState({
component: component
});
}
render() {
const C = this.state.component;
return C ? <C {...this.props} /> : null;
}
}
return AsyncComponent
}
2、在router>index.js
import React from 'react';
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import asyncComponents from "../components/AsyncComponents"
const AsyncHome = asyncComponents(() => import('../page/home/home'));
const AsyncHot = asyncComponents(() => import('../page/hot/hot'));
const router = (
<BrowserRouter>
<Switch>
<Route path='/' exact component={AsyncHome}/>
<Route path='/hot' exact component={AsyncHot}/>
</Switch>
</BrowserRouter>
);
export default router