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的父组件被卸载时,批量清除各个计时器.
随机推荐
- Go的安装
0. 环境:Ubuntu16.04 64位 1. 下载安装包,地址:https://golang.org/dl,以1.8版本为例,下载go1.8.linux-amd64.tar.gz 2. 解压 ...
- LOJ#3043.【ZJOI2019】 线段树 线段树,概率期望
原文链接www.cnblogs.com/zhouzhendong/p/ZJOI2019Day1T2.html 前言 在LOJ交了一下我的代码,发现它比选手机快将近 4 倍. 题解 对于线段树上每一个节 ...
- 使用Kazoo操作ZooKeeper服务治理
单机服务的可靠性及可扩展性有限,某台服务宕机可能会影响整个系统的正常使用:分布式服务能够有效地解决这一问题,但同时分布式服务也会带来一些新的问题,如:服务发现(新增或者删除了服务如何确保能让客户端知道 ...
- vue小白必看的生命钩子函数图解
还有3个钩子并未出现在图上: 1.activated生命周期钩子函数在keep-alive 组件激活时调用,该钩子在服务器端渲染期间不被调用. 2.deactivated生命周期钩子函数在keep-a ...
- C# 0xC0000005 捕获
[HandleProcessCorruptedStateExceptions]//捕获c++异常 [SecurityCritical]//捕获c++异常 public void xxx() { try ...
- 洛谷.5300.[GXOI/GZOI2019]与或和(单调栈)
LOJ BZOJ 洛谷 想了一个奇葩的单调栈,算的时候要在中间取\(\min\),感觉不靠谱不写了=-= 调了十分钟发现输出没取模=v= BZOJ好逗逼啊 题面连pdf都不挂了 哈哈哈哈 枚举每一位. ...
- Oracle导入数据无法导出空表的问题
Oracle 11G在用export导出时,空表不能导出,11G R2中有个新特性,当表无数据时,不分配segment,以节省空间. 那么我们应该如何导出空表: 利用如下语句生成alter语句,未每个 ...
- selenium 不同版本Driver
selenium进行UI自动化测试需要Driver支持,不同的浏览器需要不同的Driver,之前使用的Driver可以正常运行,但是总会报一些莫名的问题,经过查找,原来IE的Driver需要与sele ...
- docker用法记录
下载docker镜像 docker pull ubuntu 查看所有docker镜像 docker images 运行docker镜像且进入shell docker run -it ubuntu ba ...
- node02
1.使用已有的知识实现一个简单的登录和注册的界面 请求有请求接口有请求页面的,我们需要加以区分 以下是客户端代码 <!DOCTYPE html> <html lang="e ...