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

 

若是能帮助到你,点个赞呗 😂 

相关文章
相关标签/搜索