首先 導航鏈接應該使用 NavLink 而不再是 Link
NavLink 使用方法見 https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/api/NavLink.md
NavLink 和 PureComponent 一起使用的時候,會出現 激活鏈接樣式(當前頁面對應鏈接樣式,通過 activeClassName、activeStyle 設置) 不生效的情況。效果如下:
刷新頁面后導航激活樣式生效,點擊導航鏈接的時候 url 跳轉,但是導航激活樣式不生效。
上圖效果對應代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>NavLink And PureComponent</title> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> <script src="https://unpkg.com/react-router-dom/umd/react-router-dom.min.js"></script> <style> .menu-link { display: inline-block; width: 100px; text-decoration: none; text-align: center; background: #dedede; } .menu-link.active { background: tomato; } </style> </head> <body> <div id="app"></div> <script type="text/babel"> // import ReactRouterDOM, { HashRouter, Route } from 'react-router-dom'; // import React, { Component, PureComponent } from 'react'; const { HashRouter, Route, NavLink } = ReactRouterDOM; const { Component, PureComponent } = React; class Menu extends PureComponent { render() { return ( <div> <NavLink className="menu-link" activeClassName="active" activeStyle={{color: '#fff'}} to='/home'>首頁</NavLink> <NavLink className="menu-link" activeClassName="active" activeStyle={{color: '#fff'}} to='/help'>幫助頁</NavLink> </div> ); } } class App extends PureComponent { render() { return ( <HashRouter> <div> <Menu /> <Route path='/home' component={ () => <div>首頁內容</div> } /> <Route path='/help' component={ () => <div>幫助頁內容</div> } /> </div> </HashRouter> ); } } ReactDOM.render( <App />, document.getElementById('app') ); </script> </body> </html>
為什么不生效,我們在使用 PureComponent 之前應該知道 它相當於對組件的 props 和 state 進行淺比較,如果相等則不更新,以此來進行優化,防止多余更新。
而在上面的例子中 就相當於
class Menu extends Component { shouldComponentUpdate(props, state) { console.log(props, this.props, props === this.props); // {} {} true console.log(state, this.state, state === this.state); // null null true // 由於 props 和 state 都不發生變化 下面的表達式會返回 false 組件不會發生更新 return !shallowEqual(props, this.props) || !shallowEqual(state, this.state); } render() { return ( <div> <NavLink className="menu-link" activeClassName="active" activeStyle={{color: '#fff'}} to='/home'>首頁</NavLink> <NavLink className="menu-link" activeClassName="active" activeStyle={{color: '#fff'}} to='/help'>幫助頁</NavLink> </div> ); } }
其中淺比較函數 shallowEqual 的實現(https://blog.csdn.net/juzipidemimi/article/details/80892440)

function is(x, y) { // SameValue algorithm if (x === y) { // Steps 1-5, 7-10 // Steps 6.b-6.e: +0 != -0 // Added the nonzero y check to make Flow happy, but it is redundant,排除 +0 === -0的情況 return x !== 0 || y !== 0 || 1 / x === 1 / y; } else { // Step 6.a: NaN == NaN,x和y都不是NaN return x !== x && y !== y; } } function shallowEqual(objA, objB) { if (is(objA, objB)) { return true; } if ( typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null ) { return false; } const keysA = Object.keys(objA); const keysB = Object.keys(objB); if (keysA.length !== keysB.length) { return false; } // Test for A's keys different from B. for (let i = 0; i < keysA.length; i++) { if ( !hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]]) ) { return false; } } return true; }
所以組件 Menu 不會發生更新,所以其子組件 NavLink 自然也就不會被更新。
那么該如果解決這個問題呢?
最簡單的當然就是使用 Component 替換 PureComponent
如果不想更改 PureComponent 的話,可以通過給組件傳入當前 location 作為屬性來解決。
NavLink 是通過監聽當前所在 location 來更新鏈接樣式的,所以如果能在 location 改變的時候,更新組件就可以了,而做到這一點,只需要把 location 作為一個屬性傳入組件。
最簡單的辦法,把導航組件也作為一個 Route,並且能動態匹配所有路徑,這樣 location 會自動作為屬性被注入到組件。
class App extends PureComponent { render() { return ( <HashRouter> <div> <Route path="/:place" component={Menu} /> <Route path='/home' component={ () => <div>首頁內容</div> } /> <Route path='/help' component={ () => <div>幫助頁內容</div> } /> </div> </HashRouter> ); } }
全文參考: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md
如果能幫助到你,點個贊唄 😂