常用總結
一、基本的
1、BrowserRouter
表示一個路由的跟容器,將來所有跟路由相關的東西,都要包裹在其中
2、HashRouter
表示一個路由的跟容器,將來所有跟路由相關的東西,都要包裹在其中
3、Route 具有兩種身份: 1.它是一個路由匹配規則; 2.它是一個占位符,表示將來匹配到的組件都放到這個位置 ( 類似 vue中 <router-view/> ) <Route exact // 精確匹配 switch 與 exact 需要配合使用 path='/my' component={My}} ></Route>
4、Link 表示一個路由的連接; 在頁面渲染的是a標簽; 進行的是路由切換跳轉,整個單頁面已經切換,而且能知道指向的路徑是否是一個有效的路由 <Link to="/my">我的</Link>
5、NavLink 表示一個路由的連接; 是<Link>的一個特定版本,會在匹配上當前的url的時候給已經渲染的元素添加參數,組件的屬性有 **activeClassName(string):設置選中樣式,默認值為active **activeStyle(object):當元素被選中時,為此元素添加樣式 exact(bool):為true時,只有當導致和完全匹配class和style才會應用 strict(bool):為true時,在確定為位置是否與當前URL匹配時,將考慮位置pathname后的斜線 isActive(func)判斷鏈接是否激活的額外邏輯的功能 <NavLink to="/my">我的</NavLink> <NavLink activeStyle={{color: 'red'}} to='/about'>toAbout</NavLink> <NavLink to="/my" activeClassName="selected">My組件</NavLink>
6、Redirect 路由重定向 (1)、當用戶訪問某界面時,該界面並不存在,此時用Redirect重定向,重新跳到一個我們自定義的組件里。 (2)、一般都放在 Switch 內,且放到最后一行,即上述路由均未匹配到,則重定向到哪里 舉例 render() { return ( <Router> <div> <li><NavLink to="/">Home</NavLink></li> <li><NavLink to="/about">About</NavLink></li> <li><NavLink to="/news">News</NavLink> </li> <br/> <Switch> <Route path="/" exact component={Home} /> <Route path="/about" component={About} /> <Route path="/news" component={News} /> <Redirect to="/" /> </Switch> </div> </Router> ); }
7、Switch 路由匹配,只顯示匹配到的第一個路由,一般配合 exact,精確匹配到具體某一個路由 (1)、exact 是精准匹配,只有路徑完全一致才能被匹配到 (2)、舉例 同時加上 Switch 和 exact,擊哪個鏈接就能出來相應的頁面; 如果沒有Switch也沒有exact,不管點擊哪個鏈接都會有path=’/的頁面’, 如果不加Route 里不加 exact,那么凡是Link里面 to 的路徑包含了/( /about, /topic 都包含了 / ,當點擊about或者topic的Link的時候,path=’/'的路由都會匹配到,Switch匹配到了一個就停止向下匹配), 那么就會被匹配到,於是Switch就不繼續匹配下去 如: render() { return ( <Router> <ul> <li> <Link to="/">main</Link> </li> <li> <Link to="/about">about</Link> </li> <li> <Link to="/topic">topic</Link> </li> </ul> <Route path="/" component={Main}></Route> <Route path="/about" component={About}></Route> <Route path="/topic" component={Topic}></Route> </Router> ); } }
二、Hooks Routing相關
// Please note: You need to be using React >= 16.8 in order to use any of these hooks!
5.1版本的React-Router,帶來了useHistory,useLocation,useParams,useRouteMatch四個鈎子函數。
8、useHistory 使用history 屬性(常用) go(n) goBack(n) goForward() length location ( 路由信息 ) push replace 舉例 import { useHistory } from "react-router-dom"; function BackButton() { let history = useHistory(); return ( <> <button type="button" onClick={() => history.push("/home")}> 去home頁面 </button> <button type="button" onClick={() => history.goBack()}> 回去 </button> </> ); }
9、useLocation
查看當前路由:
const location = useLocation();
console.log(location);
輸出
pathname: "/home"
search: ""
hash: ""
state: undefined
10、useParams 獲取路由中的params。 舉例 import React from "react"; import ReactDOM from "react-dom"; import { BrowserRouter as Router, Route, Switch, useParams } from "react-router-dom"; function BlogId() { let { id } = useParams(); return <div>{id}</div>; } ReactDOM.render( <Router> <div> <Switch> <Route path="/blog/:id"> <BlogId /> </Route> </Switch> </div> </Router>, document.getElementById("root") );
11、useRouteMatch (暫無使用過) 與<Route>相同的方式匹配當前URL。在無需實際呈現<Route>的情況下訪問匹配數據最有用。 參考網上例子: // before import { Route } from 'react-router-dom' function App() { return ( <div> {/* ... */} <Route path="/BLOG/:slug/" strict sensitive render={({ match }) => { return match ? <BlogPost match={match} /> : <NotFound /> }} /> </div> ) } // after import { useRouteMatch } from 'react-router-dom' function App() { let match = useRouteMatch({ path: '/BLOG/:slug/', strict: true, sensitive: true }) return ( <div> {/* ... */} {match ? <BlogPost match={match} /> : <NotFound />} </div> ) }
三、其他
12、BrowserRouter 與 HashRouter 區別
React-Router 是建立在 history 之上的,常見的history路由方案有三種形式,分別是:
(1)、hashHistory
hashHistory 使用 URL 中的 hash(#)部分去創建路由,舉例來說,用戶訪問http://www.aaaaaa.com/,實際會看到的是http://www.aaaaaa.com/#/。
(2)、browserHistory
browserHistory 是使用 React-Router 的應用推薦的 history方案。它使用瀏覽器中的 History API 用於處理 URL,創建一個像aaaaaa.com/list/21212323 這樣真實的 URL
當刷新頁面時,瀏覽器會向服務器請求,服務器實際會去找根目錄下對應的文件,發現找不到,因為實際上我們的服務器並沒有這樣的 物理路徑/文件 或沒有配置處理這個路由,所有內容都是通過React-Router去渲染React組件,自然會報404錯誤。
(3)、createMemoryHistory (暫時沒有用到過)
Memory history 不會在地址欄被操作或讀取。這就解釋了我們是如何實現服務器渲染的。同時它也非常適合測試和其他的渲染環境(像 React Native )。和另外兩種history的一點不同是你必須創建它,這種方式便於測試。
(4)、兩種解決方法
使用hashHistory,不用做額外處理
使用browserHistory,服務器需要進行相關路由配置(由后端處理,或nginx配置)
詳見 https://www.thinktxt.com/react/2017/02/26/react-router-browserHistory-refresh-404-solution.html
13、自定義單擊事件處理程序。
e.preventDefault():阻止默認事件
e.stopPropagation():阻止事件冒泡
14、路由嵌套
詳見之前的博客
https://www.cnblogs.com/-roc/p/14518513.html
15、react 路由 進階 之 封裝使用(同vue)
詳見之前的博客
https://www.cnblogs.com/-roc/p/14504557.html
四、路由
1、路由跳轉
(1)標簽跳轉 import { Link, NavLink } from "react-router-dom"; Link, NavLink標簽,屬性為:to,如: <Link to="/my">我的</Link> <NavLink to="/my">我的</NavLink>
(2)js跳轉(類組件) push replace go goBack goForward 如 this.props.history.push() 事例,如: class Dear extends React.Component { constructor (props) { this.state = {} } toMy () { this.props.history.push('/my') } render () { return( <button onClick={this.toMy.bind(this)}/> ) } }
(3)hooks跳轉(函數組件) import { useHistory } from "react-router-dom"; const history = useHistory(); {/* history 中包含與js相同的屬性 */} function Dear () { const toMy = () => { history.push('/my') } return ( <button onClick={toMy}/> ) }
2、傳參與接收
(參考地址找不到了)
(1)params傳參(刷新頁面后參數不消失) 配置:<Route path='/demoUrl/:id' component={DemoName}></Route> 跳轉及傳遞: 標簽方式:<Link to={'/demoUrl/'+'6'}>跳轉按鈕</Link> 或:<Link to={{pathname:'/demoUrl/'+'6'}}>跳轉按鈕</Link> 導航方式:this.props.history.push('/demoUrl/'+'6') 或:this.props.history.push({pathname:'/demoUrl/'+'6'}) **************使用match*************** 獲取:this.props.match.params.id
(2)params傳參(多個參數) state={ id:88, name:'Jack', } 配置:<Route path='/demoUrl/:id/:name' component={DemoName}></Route> 跳轉及傳遞: 標簽方式:<Link to={{pathname:`/demoUrl/${this.state.id}/${this.state.name}`}}>跳轉按鈕</Link> 導航方式:this.props.history.push({pathname:`/demoUrl/${this.state.id}/${this.state.name}`}) **************使用match*************** 獲取:this.props.match.params
(3)query傳參(刷新頁面后參數消失) 配置:<Route path='/demoUrl' component={DemoName}></Route> 跳轉及傳遞: 標簽方式:<Link to={{pathname:'/demoUrl',query:{id:22,name:'dahuang'}}}>跳轉按鈕</Link> 導航方式:this.props.history.push({pathname:'/demoUrl',query:{id:22,name:'dahuang'}}) **************使用location*************** 獲取: this.props.location.query.name
(4)state傳參( 刷新頁面后參數不消失,state傳的參數是加密的,比query傳參好用) 配置:<Route path='/demoUrl' component={DemoName}></Route> 跳轉及傳遞: 標簽方式: <Link to={{pathname:'/demoUrl',state:{id:12,name:'dahuang'}}}>跳轉按鈕</Link> 導航方式:this.props.history.push({pathname:'/demoUrl',state:{id:12,name:'dahuang'}}) **************使用location*************** 獲取: this.props.location.state.name
(5)其他說明 用Hooks
(5-1)傳遞參數
import { useHistory } from 'react-router-dom'
history.push({pathname:'/' + pathName, state:{id:12, name:pathName}})
或將state改為query, params, 或aaa (名字隨意起)
只有state傳參,刷新不會丟失
(5-2)接收參數
import { useLocation } from 'react-router-dom'
const location = useLocation();
如
location.query
location.params
location.state
location.aaa ( 其實 query,params,state,都可以隨便起名字 )
只有state傳參,刷新不會丟失
3、路由守衛(或 路由攔截)
a、解釋:所謂路由守衛,就是將跳轉到某一個路由時,先進行一些邏輯判斷,若通過則進行順利跳轉,若不通過則做其他邏輯處理
b、示例:如跳轉頁面時,要談判是否在登錄狀態,若在則跳轉到該頁面,若不在則跳回登錄頁,等
c、vue中的全局守衛
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
})
vue在所有的路由跳轉前,在beforeEach中可以監聽所有的路由跳轉,如果符合規則,就進行跳轉,如果不符合,那么就跳轉到我指定的位置。
d、react-router為什么沒有呢
react-router當中,為什么不能提供同樣的api呢?作者在github中回復到:
You can do this from within your render function. JSX doesn't need an API for this because it's more flexible.
--(1)路由表
import Home from '需要展示的頁面'
var routes = [
{path: "/", name: "home", component: Home, auth: true},
{path: "/my", name: "my", component: My, auth: true},
{path: "/404", name: "404", component: 404, auth: false}
]
// auth 是否需要登錄
export default routes ;
--(2)路由高階組件 封裝
import React, { Component } from "react"; import { Route, Redirect } from "react-router-dom"; class PrivateRoute extends Component { render() { // routerConfig 為具體某項路由表信息,詳見 --(3) 具體使用 const { routerConfig, location } = this.props; const { pathname } = location; const isLogin = sessionStorage.getItem("token"); // 如果該路由不用進行權限校驗,登錄狀態下登陸頁除外 // 因為登陸后,無法跳轉到登陸頁 -------------// 這部分代碼,是為了在非登陸狀態下,訪問不需要權限校驗的路由 Start-------------- const targetRouterConfig = routerConfig.find( // find()方法,用於找出第一個符合條件的數組成員。 (item) => { // 全局去掉空格 return item.path.replace(/\s*/g,"") === pathname } ); if (targetRouterConfig && !targetRouterConfig.auth && !isLogin) { const { component } = targetRouterConfig; return <Route exact path={pathname} component={component} /> } -----------------// 這部分代碼,是為了在非登陸狀態下,訪問不需要權限校驗的路由 End-------------- -----------------// 這部分代碼,是為了在需要登陸狀態下 進行驗證-------------- if (isLogin) { // 如果是登陸狀態,想要跳轉到登陸,重定向到主頁 if (pathname === "/login") { return <Redirect to="/" />; } else { // 如果路由合法,就跳轉到相應的路由 if (targetRouterConfig) { return (<Route path={pathname} component={targetRouterConfig.component} />); } else { // 如果路由不合法,重定向到 404 頁面 return <Redirect to="/404" />; } } } else { // 非登陸狀態下,當路由合法時且需要權限校驗時,跳轉到登陸頁面,要求登陸 if (targetRouterConfig && targetRouterConfig.auth) { console.log('跳轉登錄登錄') return <Redirect to="/login" />; } else { // 非登陸狀態下,路由不合法時,重定向至 404 return <Redirect to="/404" />; } } } } export default PrivateRoute
--(3)使用 路由高階組件
import React from 'react'; import {Switch, BrowserRouter} from 'react-router-dom' // 你的高階組件 import PrivateRoute from './PrivateRoute' // 你的路由表 ,或使用 自動化配置的路由表 https://www.cnblogs.com/-roc/p/14544531.html import routes from '../views/index' function router() { return ( <BrowserRouter> <Switch> // 憑經驗編寫,有問題歡迎評論修改 routes.forEach(item => { return ( <PrivateRoute key={item.path} routerConfig={item} /> ) }) </Switch> </BrowserRouter> ); } export default router; 參考 https://www.jianshu.com/p/16f35c090706?utm_campaign=haruki https://www.jianshu.com/p/f8926ed59d25 https://zhuanlan.zhihu.com/p/162942121
4、路由懶加載
--(1)安裝 yarn add react-loadable --(2)創建通用工具類: 如: src/util/loadable.js import React from 'react'; import Loadable from 'react-loadable'; //通用的過場組件 const LoadingComponent =()=>{ return ( <div>loading</div> ) } //過場組件默認采用通用的,若傳入了loading,則采用傳入的過場組件 export default (loader,loading = LoadingComponent)=>{ return Loadable({ loader, loading }); } --(3)router里面調用方式改為如下 /*配置路由*/ import React, { Fragment } from 'react' import { BrowserRouter, Route } from 'react-router-dom' import loadable from '../util/loadable' const Home = loadable(()=>import('@pages/home')) const Routes = () => ( <BrowserRouter> <Route path="/home" component={Home}/> </BrowserRouter> ); export default Routes --(4) 封裝之后,laodable只需寫一次,改變的只是組件的引入方式,這樣一來就方便多了, react-loadable是以組件級別來分割代碼的,這意味着,我們不僅可以根據路由按需加載,還可以根據組件按需加載,使用方式和路由分割一樣,只用修改組件的引入方式即可 參考 https://www.cnblogs.com/crazycode2/p/12210778.html
寫在最后
https://reactrouter.com/web/api/Hooks/useroutematch
此為官網,感覺寫的不詳細,自己又進行了總結這篇