You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

ReactJS受保护路由初始化异常:启动后未自动跳转至登录组件

问题分析与修复方案

我仔细看了你的代码和问题描述,发现几个关键问题导致应用首次加载(访问根路径/)时没有自动跳转到登录页,只有手动输入/user/login才能进入登录组件。下面是具体的问题点和修复步骤:


核心问题点

  1. 根路径/无匹配路由:应用启动默认访问/,但你的Switch里没有定义这个路径的路由规则,所以不会触发任何跳转逻辑。
  2. ProtectedComponent未正确使用path属性:你给ProtectedComponent传了path="/dashboard",但组件内部的Route标签没有绑定这个path,导致这个受保护路由根本不会匹配/dashboard路径。
  3. 认证状态未从Redux正确传递LayoutmapStateToProps是空对象,没有把Redux里的认证状态传给ProtectedComponent,虽然你用了本地存储的token做兜底,但状态一致性会有问题。

修复后的代码

1. 修正ProtectedComponent组件

让它正确接收并使用path属性,同时优化认证判断逻辑:

import React from 'react';
import { get } from 'lodash';
import PropTypes from 'prop-types';
import { Route, Redirect } from 'react-router-dom';
import storage from '../common/storage';

const ProtectedComponent = ({ component: Component, path, isAuthenticated }) => {
  // 统一判断:优先用Redux的认证状态,其次用本地存储的token
  const isAuth = isAuthenticated || get(storage.get('user'), 'token');

  return (
    <Route
      path={path}
      render={(routeProps) => 
        // 把路由props传递给子组件,避免后续路由相关功能失效
        isAuth ? <Component {...routeProps} /> : <Redirect to="/user/login" />
      }
    />
  );
};

ProtectedComponent.defaultProps = {
  isAuthenticated: false,
};

ProtectedComponent.propTypes = {
  component: PropTypes.any.isRequired,
  isAuthenticated: PropTypes.bool,
  path: PropTypes.string.isRequired, // 新增path的必填校验
};

export default ProtectedComponent;

2. 修正Layout组件

添加根路径的重定向规则,同时正确从Redux获取认证状态:

import React, { memo } from 'react'; // 注意要导入memo,原代码里漏了
import { connect } from 'react-redux';
import Loadable from 'react-loadable';
import { BreadcrumbsItem } from 'react-breadcrumbs-dynamic';
import { Switch, Route, Redirect, withRouter } from 'react-router-dom';
import { MAINTENANCE_MODE } from '../../common/constants';
import classes from './Layout.view.scss';
import ProtectedComponent from '../../components/ProtectedComponent';
import storage from '../common/storage'; // 导入storage用于根路径判断

const Loading = () => 'Loading...';

const Auth = Loadable({
  loader: () => import('../auth/Auth.container'),
  loading: Loading,
});

const Maintenance = Loadable({
  loader: () => import('../../components/Maintenance/Maintenance'),
  loading: Loading,
});

const Dashboard = Loadable({
  loader: () => import('../dashboard/views/dashboard'),
  loading: Loading,
});

const Layout = ({ isAuthenticated }) => {
  return (
    <>
      <BreadcrumbsItem to="/" key="layout-breadcrumb">
        Home
      </BreadcrumbsItem>
      <div className={classes.layout}>
        <div className={classes.main}>
          <div className={classes.pageContent}>
            {MAINTENANCE_MODE === 'Yes' ? (
              <Route path="/" component={Maintenance} />
            ) : (
              <Switch>
                {/* 登录路由 */}
                <Route exact path="/user/login" component={Auth} />
                {/* 受保护的仪表盘路由:正确传递isAuthenticated */}
                <ProtectedComponent 
                  path="/dashboard" 
                  component={Dashboard} 
                  isAuthenticated={isAuthenticated}
                />
                {/* 根路径处理:首次加载时自动跳转 */}
                <Route 
                  exact path="/" 
                  render={() => 
                    // 已认证跳仪表盘,未认证跳登录
                    isAuthenticated || get(storage.get('user'), 'token') 
                      ? <Redirect to="/dashboard" /> 
                      : <Redirect to="/user/login" />
                  }
                />
                {/* 兜底路由:处理所有未匹配的路径,重定向到根路径 */}
                <Route render={() => <Redirect to="/" />} />
              </Switch>
            )}
          </div>
        </div>
      </div>
    </>
  );
};

Layout.defaultProps = {};

Layout.propTypes = {};

// 从Redux store获取认证状态,根据你的实际store结构调整路径
const mapStateToProps = (state) => ({
  isAuthenticated: state.auth?.isAuthenticated || false,
});

export default withRouter(connect(mapStateToProps)(memo(Layout)));

额外注意事项

  • 请根据你Redux store的实际结构调整mapStateToProps里的state.auth?.isAuthenticated路径,如果你的认证状态存在其他位置,要对应修改。
  • 根路径的重定向逻辑确保了首次加载时,无论用户是否认证,都会跳转到对应的页面(登录或仪表盘)。
  • ProtectedComponent现在会把路由相关的props(比如historymatch)传递给子组件,避免后续在Dashboard里使用路由功能时出现问题。

内容的提问来源于stack exchange,提问作者Hanzlah Tariq

火山引擎 最新活动