React 中 Link 和 NavLink 組件 activeClassName、activeStyle 屬性不生效的問題

首先 導航連接應該使用  NavLink 而再也不是  Link html

 NavLink 使用方法見 https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/api/NavLink.mdreact

 

 NavLink 和  PureComponent 一塊兒使用的時候,會出現 激活連接樣式(當前頁面對應連接樣式,經過 activeClassName、activeStyle 設置) 不生效的狀況。效果以下:git

刷新頁面後導航激活樣式生效,點擊導航連接的時候 url 跳轉,可是導航激活樣式不生效。github

上圖效果對應代碼:api

<!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 進行淺比較,若是相等則不更新,以此來進行優化,防止多餘更新。babel

而在上面的例子中 就至關於react-router

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)app

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;
}
View Code

 

因此組件  Menu 不會發生更新,因此其子組件  NavLink 天然也就不會被更新。dom

那麼該若是解決這個問題呢?ide

最簡單的固然就是使用  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

 

若是能幫助到你,點個讚唄 😂 

相關文章
相關標籤/搜索