昨日在一个使用了React Router的项目中发现一个问题,一个组件一直渲染不出来,排查了一个下午才定位到问题所在。为了简化问题,demo代码如下
class Index extends React.Component { render() { return ( <Provider store={store}> <BrowserRouter> <Route path="/" component={Home}/> </BrowserRouter> </Provider> ) } } class Home extends React.Component { handle = () => { return (<WrappedTest/>); } render() { return ( <div> <Route path="/home" render={this.handle}/> </div> ) } } class Test extends React.Component { componentWillMount() { console.log('Test componentWillMount'); } render() { return ( <div> <Link to="/home/test">show</Link> <Route path="/home/test" render={() => <h3>hi</h3>}/> </div> ) } } const WrappedTest = connect()(Test); ReactDOM.render(<Index/>,document.getElementById('root'));
入口url是"/home",初次进入页面时Test组件就已经被挂载了,上面有一个show按钮,期望效果是点击按钮时跳到"/home/test",而这个路由会显示"hi"字符串。
可是实际点击后发现地址是跳转了,但是字符串没有显示出来,排查后发现是Test的render没有被调用。
这个问题由两个因素引起,第一个是因为redux的connect函数包装过的组件默认会有一个优化,第二个是因为react-router中的内联渲染方式,当这两者一起出现时就可能会出现这样的问题。
对于第一个原因,connect在包装组件时会对组件的shouldComponentUpdate方法有一个默认的实现,也就是对组件的props进行一个浅比较,如果props没有变化则不会调用render方法,比如上面的例子中只是点击了link,而没有改变任何prop,所以render方法没有被触发。
第二个原因,在react-router v4中,有两种常见的渲染组件的方式:component和render。前者是使用React.createElement方法新建一个元素,而后者仅仅是调用现有组件的render方法。
所以对于上面的例子来说,有两种方式可以解决,第一种是在connect时关闭这种优化
const WrappedTest = connect(null,null,{pure: false})(Test);注意第4个参数,pure设置为false即可。表示不进行浅对比,让shouldComponentUpdate总是返回true从而触发渲染。
第二种办法是在route中使用component而不是render。
<Route path="/home" component={WrappedTest}/>
参考资料:
原文链接:https://www.f2er.com/react/303377.html