React Router登录认证后重定向 添加location state触发无限渲染问题
问题根因及修复方案
1. 修复路由配置结构错误
你当前把/login路由定义在了<Switch>标签外部,会导致每次路由匹配都会先触发Login路由的渲染逻辑,和内部PrivateRoute的重定向逻辑形成冲突,修改配置如下:
<Router history={history}> <ThemeProvider theme={theme}> <CssBaseline /> <Alert th={ui.darkTheme} /> <UpdateApp /> <Switch> {/* 把login路由移到Switch最顶部 */} <Route path="/login" exact component={Login} /> <PrivateRoute path="/" exact component={Homepage} /> <PrivateRoute path="/info" exact component={Infos} /> <PrivateRoute path="/info/add" exact component={AddInfo} /> <PrivateRoute path="/info/:id" exact component={ShowInfo} /> <PrivateRoute path="/info/:id/edit" exact component={EditInfo} /> <PrivateRoute component={Four} /> </Switch> </ThemeProvider> </Router>
2. 给useSelector添加浅层对比避免不必要重渲染
默认useSelector用严格等于(===)判断返回值是否变化,如果你Redux里更新auth状态时每次返回新对象,哪怕属性值完全没变也会触发PrivateRoute重渲染,修改如下:
// 从react-redux导入shallowEqual import { shallowEqual, useSelector } from 'react-redux'; // 修改useSelector调用 const auth = useSelector((state: RootState) => state.auth, shallowEqual);
3. 优化Redirect的to对象引用
你当前在render函数里直接写对象字面量作为to参数,每次render都会生成新的对象,触发Redirect重复执行重定向逻辑,用useMemo缓存from的值即可:
const PrivateRoute = ({ component: Component, exact, path, }: RouteProps): JSX.Element => { if (!Component) return <div />; const classes = useStyles(); const auth = useSelector((state: RootState) => state.auth, shallowEqual); return ( <Route path={path} exact={exact} render={(props) => { if (auth.loading) { return ( <Backdrop className={classes.backdrop} open> <CircularProgress color="inherit" /> </Backdrop> ) } if (auth.isAuthenticated) { return <Component {...props} /> } // 只有props.location变化时才生成新的to对象 const redirectTo = useMemo(() => ({ pathname: '/login', state: { from: props.location } }), [props.location]) return <Redirect to={redirectTo} /> }} /> ); };
4. 校验Login组件的跳转逻辑
确认登录成功后的跳转逻辑不会重复触发重定向,参考写法如下:
// Login组件登录成功后的跳转逻辑 const handleLogin = async () => { // 调用登录接口,更新Redux的auth状态 await requestLogin(loginForm); dispatch(updateAuth({ isAuthenticated: true, loading: false })); // from值判空,默认跳首页,避免空值报错 const targetPath = location.state?.from?.pathname || '/'; // 用replace替代push,避免用户点后退回到登录页 history.replace(targetPath); }
完成以上修改即可解决无限渲染循环问题。
内容的提问来源于stack exchange,提问作者lulu33
相关产品推荐
相关产品推荐

