如何解决React Router中被connect包裹的组件重复挂载问题
首先咱们拆解下你遇到的问题:你已经尝试用Route的render prop来渲染被Redux connect()包裹的HandleSignIn组件,但它还是触发了两次componentDidMount。结合你的代码和场景,我整理了几个最可能的原因和对应的解决办法:
1. 检查是否开启了React严格模式(最常见元凶)
React的StrictMode会在开发环境下刻意重复调用某些生命周期方法(比如componentDidMount、render),目的是帮你检测代码中的副作用问题。如果你的项目入口文件(比如index.js)里用<React.StrictMode>包裹了根组件,那这大概率就是你看到两次mounted弹窗的原因。
解决办法:
- 开发环境下可以暂时注释掉StrictMode验证:
// index.js // 把下面这行注释掉 // <React.StrictMode> <RoutedApp /> // </React.StrictMode>
- 放心,生产环境下StrictMode会自动失效,上线后不会有这个问题。
2. 确保connect包裹的组件是稳定引用
虽然你已经提前定义了HandleSignInContainer并导出了connect后的组件,但如果在Route的render prop里动态创建组件(比如直接在render里调用connect),会导致每次RoutedApp重新渲染时生成新的组件类型,触发卸载再挂载。
你的当前写法是对的(提前导出connect后的组件),但要避免这种错误写法:
// 错误示例:每次render都会创建新的组件实例 <Route path={routes.HANDLE_SIGN_IN} render={props => connect(null, { signInAction })(HandleSignInContainer)(props)} />
3. 给Route组件添加稳定的key
当RoutedApp的signedIn prop变化时,整个组件会重新渲染,Switch里的Route可能会因为props变化而重新生成组件实例。给每个Route添加固定的key可以帮助React识别这是同一个组件,避免重复挂载。
修改你的RoutedApp代码:
const RoutedApp = ({ signedIn }) => { return ( <BrowserRouter> <Switch> <Route key="handle-sign-in" path={routes.HANDLE_SIGN_IN} render={props => <HandleSignIn {...props} />} /> <PublicRoute key="landing" exact path={routes.LANDING} signedIn={signedIn} component={LandingContainer} /> <PrivateRoute key="home" exact path={routes.HOME} signedIn={signedIn} component={HomeContainer} /> <Route key="404" component={PageNotFoundContainer} /> </Switch> </BrowserRouter> ); };
4. 排查跳转逻辑是否重复触发路由变化
你在componentDidMount里用this.props.history做跳转,建议确认signInAction里是否也有跳转逻辑。如果action和组件里都调用了history.push('/home'),可能会导致路由快速变化,看起来像是组件重复挂载(实际是卸载后又被路由匹配到?不过你的场景里登录后应该跳转到首页,登录路由的组件会被卸载,所以这个概率较低,但可以排查下)。
建议先从StrictMode开始排查,这是很多开发者遇到两次挂载的常见原因。如果去掉StrictMode后问题解决,那就是这个原因;如果还没解决,再尝试给Route加key或者检查组件引用的稳定性。
内容的提问来源于stack exchange,提问作者Colin Burke

