React 中 Link 和 NavLink 组件 activeClassName、activeStyle 属性不生效的问题
首先 导航链接应该使用 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
如果能帮助到你,点个赞呗
React 中 Link 和 NavLink 组件 activeClassName、activeStyle 属性不生效的问题的更多相关文章
- React 深入系列1:React 中的元素、组件、实例和节点
文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列,深入讲解了React中的重点概念.特性和模式等,旨在帮助大家加深对React的理解,以及在项目中 ...
- React中的高阶组件,无状态组件,PureComponent
1. 高阶组件 React中的高阶组件是一个函数,不是一个组件. 函数的入参有一个React组件和一些参数,返回值是一个包装后的React组件.相当于将输入的React组件进行了一些增强.React的 ...
- React中的高阶组件
高阶组件(HOC, High-Order Component)是React中用于重组组件逻辑的高级技术,是一种编程模式而不是React的api. 直观来讲,高阶组件是以某一组件作为参数返回一个新组件的 ...
- 理解React中es6方法创建组件的this
首发于:https://mingjiezhang.github.io/(转载请说明此出处). 在JavaScript中,this对象是运行时基于函数的执行环境(也就是上下文)绑定的. 从react中的 ...
- react中直接调用子组件的方法(非props方式)
我们都知道在 react中,若要在父组件调用子组件的方法,通常我们会采用在父组件定义一个方法,作为props转给子组件,然后执行该方法,可以获取到子组件传回的参数以得到我们的目的. 显而易见,这个执行 ...
- React中使用Ant Table组件
一.Ant Design of React http://ant.design/docs/react/introduce 二.建立webpack工程 webpack+react demo下载 项目的启 ...
- 在React中写一个Animation组件,为组件进入和离开加上动画/过度
问题 在单页面应用中,我们经常需要给路由的切换或者元素的挂载和卸载加上过渡效果,为这么一个小功能引入第三方框架,实在有点小纠结.不如自己封装. 思路 原理 以进入时opacity: 0 --> ...
- 如何在react中实现一个倒计时组件
倒计时组件 import React, { Component } from 'react' import $ from 'jquery' import "../../css/spellTE ...
- 批量清除react中的计时器小组件
在Timers的父组件被卸载时,批量清除各个计时器.
随机推荐
- vsftp搭建
(1)下载 yum install -y vsftpd (2)目录详情 /etc/vsftpd/vsftpd.conf:vsftpd 的核心配置文件 /etc/vsftpd/ftpusers:用于指定 ...
- 0 - Dao层(数据访问层设计)
1. Dao 使用接口设计 2. Dao 没有实现代码, 使用模板实现(通过DynamicProxy+Dapper) 3. 模板格式暂定使用Ader Template 来自为知笔记(Wiz)
- python全栈开发day113-DBUtils(pymysql数据连接池)、Request管理上下文分析
1.DBUtils(pymysql数据连接池) import pymysql from DBUtils.PooledDB import PooledDB POOL = PooledDB( creato ...
- Python实现RSA无填充加密,兼容BouncyCastle
场景 某系统登录时密码经过前台rsa加密传给后端,为实现模拟登录需要原样生成加密串. 分析 前台通过RSA.js.BigInt.js.Barrett.js三个js文件实现加密,公钥通过ajax请求获得 ...
- kafka 客户端 producer 配置参数
属性 描述 类型 默认值 bootstrap.servers 用于建立与kafka集群的连接,这个list仅仅影响用于初始化的hosts,来发现全部的servers.格式:host1:port1,ho ...
- 2019全国大学生信息安全竞赛初赛pwn前四题writeup—栈部分
ret to libc技巧:https://blog.csdn.net/zh_explorer/article/details/80306965 如何leak出libc地址:基地址+函数在libc中的 ...
- Codeforces 446A. DZY Loves Sequences (线性DP)
<题目链接> 题目大意: 给定一个长度为$n$的序列,现在最多能够改变其中的一个数字,使其变成任意值.问你这个序列的最长严格上升子段的长度是多少. #include <bits/st ...
- ELK:logstash和filebeat6.0及以上版本的配置
filebeat6.0版本以上没有document_type字段,因此需要另外标记下或者代替document_type字段的功能 案例如下: fielbeat5.5的配置 logstash5.5的配置 ...
- HBase数据库增删改查常用命令操作
最近测试用到了Hbase数据库,新建一个学生表,对表进行增删改查操作,把常用命令贴出来分享给大家~ 官方API:https://hbase.apache.org/book.html#quickstar ...
- CentOS7下使用yum安装MariaDB
从CentOS 7开始,使用 MariaDB 替代默认的 MySQL.MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的目的是完全兼容MyS ...