引言
在上一篇中,我們學習了 React 中使用路由技術,以及如何使用 MyNavLink 去優化使用路由時的代碼冗余的情況。
這一節我們繼續上一篇 React 路由進行一些補充
1. Switch 解決相同路徑問題
首先我們看一段這樣的代碼
<Route path="/home" component={Home}></Route>
<Route path="/about" component={About}></Route>
<Route path="/about" component={About}></Route>
這是兩個路由組件,在2,3行中,我們同時使用了相同的路徑 /about
我們發現它出現了兩個 about 組件的內容,那這是為什么呢?
其實是因為,Route 的機制,當匹配上了第一個 /about 組件后,它還會繼續向下匹配,因此會出現兩個 About 組件,這時我們可以采用 Switch 組件進行包裹
<Switch><Route path="/home" component={Home}></Route><Route path="/about" component={About}></Route><Route path="/about" component={About}></Route>
</Switch>
在使用 Switch 時,我們需要先從 react-router-dom 中暴露出 Switch 組件
這樣我們就能成功的解決掉這個問題了
2. 解決二級路由樣式丟失的問題
當我們將路徑改寫成 path="/ljc/about" 這樣的形式時,我們會發現當我們強制刷新頁面的時候,頁面的 CSS 樣式消失了。這是因為,我們在引入樣式文件時,采取的是相對路徑,當我們使用二級路由的時候,會使得請求的路徑發生改變,瀏覽器會向 localhost:3000/ljc 下請求 css 樣式資源,這并不是我們想要的,因為我們的樣式存放于公共文件下的 CSS 文件夾中。
我們有幾種方法,可以解決這個問題
- 將樣式引入的路徑改成絕對路徑
- 引入樣式文件時不帶 .
- 使用 HashRouter
我們一般采用第一種方式去解決
3. 路由的精準匹配和模糊匹配
路由的匹配有兩種形式,一種是精準匹配一種是模糊匹配,React 中默認開啟的是模糊匹配
模糊匹配可以理解為,在匹配路由時,只要有匹配到的就好了
精準匹配就是,兩者必須相同
我們展示一個模糊匹配的例子
<MyNavLink to = "/home/a/b" >Home</MyNavLink>
這個標簽匹配的路由,我們可以拆分成 home a b,將會根據這個先后順序匹配路由
<Route path="/home"component={Home}/>
就可以匹配到上面的這個路由,因為它匹配的是 home
當匹配的路由改成下面這樣時,就會失敗。它會按照第一個來匹配,如果第一個沒有匹配上,那就會失敗,這里的 a 和 home 沒有匹配上,很顯然會失敗
<Route path="/a" component={Home}/>
當我們開啟了精準匹配后,就我們的第一種匹配就不會成功,因為精準匹配需要的是完全一樣的值,開啟精準匹配采用的是 exact 來實現
<Route exact={true} ?path="/home" component={Home}/>
4. 重定向路由
在我們寫好了這些之后,我們會發現,我們需要點擊任意一個按鈕,才會去匹配一個組件,這并不是我們想要的,我們想要頁面一加載上來,默認的就能匹配到一個組件。
這個時候我們就需要時候 Redirecrt 進行默認匹配了。
<Redirect to="/home" />
當我們加上這條語句時,頁面找不到指定路徑時,就會重定向到 /home 頁面下因此當我們請求3000端口時,就會重定向到 /home 這樣就能夠實現我們想要的效果了
5. 嵌套路由
嵌套路由也就是我們前面有提及的二級路由,但是嵌套路由包括了二級、三級...還有很多級路由,當我們需要在一個路由組件中添加兩個組件,一個是頭部,一個是內容區
我們將我們的嵌套內容寫在相應的組件里面,這個是在 Home 組件的 return 內容
<div><h2>Home組件內容</h2><div><ul className="nav nav-tabs"><li><MyNavLink className="list-group-item" to="/home/news">News</MyNavLink></li><li><MyNavLink className="list-group-item " to="/home/message">Message</MyNavLink></li></ul>{/* 注冊路由 */}<Switch><Route path="/home/news" component={News} /><Route path="/home/message" component={Message} /></Switch></div>
</div>
在這里我們需要使用嵌套路由的方式,才能完成匹配
首先我們得 React 中路由得注冊是有順序得,我們在匹配得時候,因為 Home 組件是先注冊得,因此在匹配的時候先去找 home 路由,由于是模糊匹配,會成功的匹配
在 Home 組件里面去匹配相應的路由,從而找到 /home/news 進行匹配,因此找到 News 組件,進行匹配渲染
如果開啟精確匹配的話,第一步的 /home/news 匹配 /home 就會卡住不動,這個時候就不會顯示有用的東西了!
6. 傳遞 params 參數
首先我們需要實現的效果是,點擊消息列表,展示出消息的詳細內容
這個案例實現的方法有三種,第一種就是傳遞 params 參數,由于我們所顯示的數據都是從數據集中取出來的,因此我們需要有數據的傳輸給 Detail 組件
我們首先需要將詳細內容的數據列表,保存在 DetailData 中,將消息列表保存在 Message 的 state 中。
我們可以通過將數據拼接在路由地址末尾來實現數據的傳遞
?<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
如上,我們將消息列表的 id 和 title 寫在了路由地址后面
這里我們需要注意的是:需要采用模板字符串以及 $ 符的方式來進行數據的獲取
在注冊路由時,我們可以通過 :數據名 來接收數據
<Route path="/home/message/detail/:id/:title" component={Detail} />
如上,使用了 :id/:title 成功的接收了由 Link 傳遞過來的 id 和 title 數據
這樣我們既成功的實現了路由的跳轉,又將需要獲取的數據傳遞給了 Detail 組件
我們在 Detail 組件中打印 this.props 來查看當前接收的數據情況
我們可以發現,我們傳遞的數據被接收到了對象的 match 屬性下的 params 中
因此我們可以在 Detail 組件中獲取到又 Message 組件中傳遞來的 params 數據
并通過 params 數據中的 id 值,在詳細內容的數據集中查找出指定 id 的詳細內容
const { id, title } = this.props.match.params
const findResult = DetailData.find((detailObj) => {return detailObj.id === id
})
最后渲染數據即可
7. 傳遞 search 參數
我們還可以采用傳遞 search 參數的方法來實現
首先我們先確定數據傳輸的方式
我們先在 Link 中采用 ? 符號的方式來表示后面的為可用數據
<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>
采用 search 傳遞的方式,無需在 Route 中再次聲明,可以在 Detail 組件中直接獲取到
我們可以發現,我們的數據保存在了 location 對象下的 search 中,是一種字符串的形式保存的,我們可以引用一個庫來進行轉化 querystring
import qs from 'querystring'
這個庫是 React 中自帶有的,它有兩個方法,一個是 parse 一個是 stringify
我們可以采用 parse 方法,將字符串轉化為鍵值對形式的對象
const { search } = this.props.location
const { id, title } = qs.parse(search.slice(1))
這樣我們就能成功的獲取數據,并進行渲染
tips:無需聲明接收
8. 傳遞 state 參數
采用傳遞 state 參數的方法,是我覺得最完美的一種方法,因為它不會將數據攜帶到地址欄上,采用內部的狀態來維護
<Link to={{ pathname: '/home/message/detail', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link>
首先,我們需要在 Link 中注冊跳轉時,傳遞一個路由對象,包括一個 跳轉地址名,一個 state 數據,這樣我們就可以在 Detail 組件中獲取到這個傳遞的 state 數據
注意:采用這種方式傳遞,無需聲明接收
我們可以在 Detail 組件中的 location 對象下的 state 中取出我們所傳遞的數據
const { id, title } = this.props.location.state
直接使用即可~
解決清除緩存造成報錯的問題,我們可以在獲取不到數據的時候用空對象來替代,例如,
const { id, title } = this.props.location.state || {}
當獲取不到 state 時,則用空對象代替
這里的 state 和狀態里的 state 有所不同