React Router 4.2.2中withRouter获取路径异常,activeClassName失效怎么办?
看起来你的问题核心在于NavBar组件的路由上下文以及NavLink的激活逻辑,我来帮你拆解一下:
为什么this.props.match始终返回根路径信息?
你的NavBar组件直接作为App的子组件存在,并没有被任何Route组件包裹。即使你用了withRouter,它注入的match对象对应的是父组件(App)的路由匹配信息——而App本身处于路由树的根节点(没有被Route匹配),所以自然拿到的是根路径/的match数据。这是正常现象,因为全局导航组件本来就不属于某个具体路由的嵌套部分,不需要依赖某个路由的match。
为什么activeClassName不生效?
针对这个问题,你可以尝试以下几种解决方案,按优先级排序:
1. 移除NavLink上的exact属性
你给NavLink加了exact,这会让它只有在当前路径与to的路径完全一致时才会激活。但你的目标路由/characters和/locations都是一级路由,没有嵌套,其实不需要exact限制。修改后的代码:
<li><NavLink to="/characters" activeClassName="active">Characters</NavLink></li> <li><NavLink to="/locations" activeClassName="active">Locations</NavLink></li>
2. 移除withRouter对NavBar的包裹
NavLink本身就是路由感知组件,它内部会通过路由上下文自动获取当前location信息,不需要依赖withRouter注入的props。你可以直接导出NavBar:
// 替换原来的 export default withRouter(NavBar); export default NavBar;
3. 手动指定isActive判断函数(兜底方案)
如果上面的方法都不生效,你可以手动通过location判断激活状态,给NavLink传递isActive属性:
<li> <NavLink to="/characters" activeClassName="active" isActive={(match, location) => location.pathname === '/characters'} > Characters </NavLink> </li> <li> <NavLink to="/locations" activeClassName="active" isActive={(match, location) => location.pathname === '/locations'} > Locations </NavLink> </li>
4. 确认入口文件的Router包裹
最后检查一下你的入口文件(比如index.js)是否正确用BrowserRouter包裹了整个App,这是路由功能正常工作的前提:
import { BrowserRouter } from 'react-router-dom'; import App from './App'; ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById('root') );
关于手动实现active类的替代方案
你提到的通过this.props.location.pathname自行判断激活状态也是可行的,比如:
class NavBar extends React.Component { render() { const { pathname, history } = this.props.location; return ( <div className="navbar-fixed"> <nav className="light-blue lighten-1"> <div className="nav-wrapper container"> <a className="brand-logo">Logo</a> <ul id="nav-mobile" className="right hide-on-med-and-down"> <li> <a href="/characters" className={pathname === '/characters' ? 'active' : ''} onClick={(e) => { e.preventDefault(); history.push('/characters'); }} > Characters </a> </li> <li> <a href="/locations" className={pathname === '/locations' ? 'active' : ''} onClick={(e) => { e.preventDefault(); history.push('/locations'); }} > Locations </a> </li> </ul> </div> </nav> </div> ); } } export default withRouter(NavBar);
不过更推荐使用NavLink的内置逻辑,它已经封装了路由匹配的细节,更简洁可靠。
内容的提问来源于stack exchange,提问作者wobsoriano

