React Router 4动态路由重构后无法正确重新渲染问题
解决React Router 4路由切换时组件内容不更新的问题
你的问题根源很清晰:组件的constructor只会在首次挂载时执行一次。你在constructor里把this.props.match.params.product存入了state,但当路由切换时,props发生了变化,可state并不会自动同步更新,所以组件一直显示的是初始化时的旧数据——只有刷新页面重新挂载组件,constructor才会再次执行,state才会拿到新的参数。
而且你提到的UNSAFE_componentWillReceiveProps确实已经被React官方标记为不安全,不推荐使用,我们有更合适的解决办法,分两种情况来说:
最优方案:直接使用props,不维护冗余state
既然你的组件内容完全依赖路由参数(props),根本不需要把这些值存到state里,直接在render中使用最新的props即可,这样代码更简洁,也彻底避免了状态同步的问题:
修改TopNavSub.js如下:
import React, { Component } from 'react'; import { subNavLinks } from './navigationData'; class TopNavSub extends Component { render() { // 直接从props中获取最新的路由参数 const { product } = this.props.match.params; // 根据参数获取对应的导航链接 const currentNavLinks = subNavLinks[product]; // 如果没有匹配到对应的产品,返回null避免报错 if (!currentNavLinks) return null; return ( <ul> {currentNavLinks.map(item => ( <li key={item}>{item}</li> ))} </ul> ) } }; export default TopNavSub;
这样每次路由切换时,props更新会触发组件重新render,自然会获取到最新的product参数,渲染对应的内容。
备选方案:当确实需要同步props到state时(不推荐此场景使用)
如果你的业务逻辑确实需要把props的值存入state(比如需要基于这个值做复杂的状态处理),可以使用React推荐的生命周期方法来监听props变化并更新state:
方法1:使用componentDidUpdate
import React, { Component } from 'react'; import { subNavLinks } from './navigationData'; class TopNavSub extends Component { constructor(props) { super(props); this.state = { product: props.match.params.product, }; } componentDidUpdate(prevProps) { // 对比前后props中的路由参数,变化时更新state if (prevProps.match.params.product !== this.props.match.params.product) { this.setState({ product: this.props.match.params.product, }); } } render() { const currentNavLinks = subNavLinks[this.state.product]; if (!currentNavLinks) return null; return ( <ul> {currentNavLinks.map(item => ( <li key={item}>{item}</li> ))} </ul> ) } }; export default TopNavSub;
方法2:使用static getDerivedStateFromProps(React官方推荐的替代方案)
这是React为了替代不安全的生命周期而推出的静态方法,用于在props变化时更新state:
import React, { Component } from 'react'; import { subNavLinks } from './navigationData'; class TopNavSub extends Component { state = { product: this.props.match.params.product, }; static getDerivedStateFromProps(nextProps, prevState) { // 检测路由参数是否变化,变化则返回新的state if (nextProps.match.params.product !== prevState.product) { return { product: nextProps.match.params.product, }; } // 不需要更新时返回null return null; } render() { const currentNavLinks = subNavLinks[this.state.product]; if (!currentNavLinks) return null; return ( <ul> {currentNavLinks.map(item => ( <li key={item}>{item}</li> ))} </ul> ) } }; export default TopNavSub;
总结
- 优先选择直接使用props的方案,这是React的最佳实践,减少不必要的state,避免状态不同步的问题。
- 绝对不要使用
UNSAFE_componentWillReceiveProps,它存在潜在的bug和性能问题,React未来版本可能会移除它。
内容的提问来源于stack exchange,提问作者Brandon Benefield
相关产品推荐
相关产品推荐

