【问题标题】:Routing issue with reactjs router 4 and reduxreactjs router 4和redux的路由问题
【发布时间】:2023-04-11 03:34:01
【问题描述】:

您好,我正在构建一个使用 reactjs redux 和 react-router-dom 的项目。

由于一些我无法弄清楚的奇怪原因,当我导航到 http://localhost:3000 时,我收到以下错误: Warning: You tried to redirect to the same route you're currently on: "/signin"

我从类似的问题中尝试了很多东西,但没有运气。也许Switch 不起作用?或者我需要一双新鲜的眼睛,因为这可能很明显......

下面是我的源代码:

router.jsx

import React from 'react';
import { connect } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import Routes from '../routes/index.jsx';

// Global Components
import CustomNavbar from '../navbar/index.jsx';
import Sidemenu from '../sidemenu/index.jsx';
import Emulator from '../emulator/index.jsx';

// Styles
import 'font-awesome/css/font-awesome.css';
import 'bootstrap/dist/css/bootstrap.css';
import '../../sass/style.scss';
import '../../sass/router.scss';

class CustomRouter extends React.Component {

    constructor(props) {
        super(props);
    }

    isSignedin = () => {
        return this.props.user.authenticated;
    }

    isSidemenuOpen = () => {
        return this.props.app.sidemenu.open;
    }

    isEmulatorOpen = () => {
        return this.props.app.emulator.open;
    }

    getWrapperClassName = () => {

        let classList = [];

        if (this.isSignedin()) {
            classList.push('authenticated');
        }

        if (this.isSidemenuOpen()) {
            classList.push('sidemenu');
        }

        if (this.isEmulatorOpen()) {
            classList.push('emulator');
        }

        return classList.join(' ');

    }

    render = () => {

        return (
            <BrowserRouter>

                <div id='wrapper' className={this.getWrapperClassName()}>

                    {(() => {

                        if (this.isSignedin()) {

                            return (
                                <React.Fragment>
                                    <Sidemenu />
                                    <CustomNavbar />
                                    <Emulator />
                                </React.Fragment>
                            )

                        } else {
                            return null;
                        }

                    })()}

                    <div id='page-content'>
                        <div className='p-4'>
                            <Routes />
                        </div>
                    </div>

                </div>

            </BrowserRouter>
        )

    }

}

const mapStateToProps = (state) => {
    return {
        app: state.appReducer,
        user: state.userReducer
    }
}

export default connect(mapStateToProps, null, null, { withRef: true })(CustomRouter);

routes.jsx

import React from 'react';
import { withRouter, Switch, Route } from 'react-router-dom';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import AuthenticatedRoute from '../authenticatedRoute/index.jsx';
import UnauthenticatedRoute from '../unauthenticatedRoute/index.jsx';

// Root Components
import Home from '../routes/home/index.jsx';
import Dashboard from '../routes/dashboard/index.jsx';
import Bots from '../routes/bots/index.jsx';
import Actions from '../routes/actions/index.jsx';
import Flows from '../routes/flows/index.jsx';
import Sessions from '../routes/sessions/index.jsx';
import Users from '../routes/users/index.jsx';
import Signin from '../routes/signin/index.jsx';
import Signup from '../routes/signup/index.jsx';
import Reset from '../routes/reset/index.jsx';
import NotFound from '../routes/notfound/index.jsx';

const Routes = ({ location }) => {
    return (
        <TransitionGroup className='transition-group'>
            <CSSTransition key={location.key} classNames='fade' timeout={{ enter: 300, exit: 300 }}>
                <section className='route-group'>
                    <Switch location={location} >
                        <Route path='/' component={Home} exact={true}></Route>
                        <UnauthenticatedRoute path='/signin' component={Signin} exact={true}></UnauthenticatedRoute>
                        <UnauthenticatedRoute path='/signup' component={Signup} exact={true}></UnauthenticatedRoute>
                        <UnauthenticatedRoute path='/reset' component={Reset} exact={true}></UnauthenticatedRoute>
                        {/* <AuthenticatedRoute path='/dashboard' component={Dashboard} exact={true}></AuthenticatedRoute>
                        <AuthenticatedRoute path='/bots/:botId?' component={Bots} exact={true}></AuthenticatedRoute>
                        <AuthenticatedRoute path='/actions/:actionId?' component={Actions} exact={true}></AuthenticatedRoute>
                        <AuthenticatedRoute path='/flows/:flowId?' component={Flows} exact={true}></AuthenticatedRoute>
                        <AuthenticatedRoute path='/users/:userId?' component={Users} exact={true}></AuthenticatedRoute>
                        <AuthenticatedRoute path='/sessions/:sessionId?' component={Sessions} exact={true}></AuthenticatedRoute> */}
                        <Route path='*' component={NotFound}></Route>
                    </Switch>
                </section>
            </CSSTransition>
        </TransitionGroup>
    )
}

export default withRouter(Routes);

home.jsx(/虚拟路由组件)

它仅用于将您重定向到 /dashboard 或 /signin 相应地

import React from 'react';
import { connect } from 'react-redux';
import { Redirect } from "react-router-dom";

import '../../../sass/home.scss';

class Home extends React.Component {

    constructor(props) {

        super(props);

        this.state = this.getInitialState();

    }

    getInitialState = () => {
        return {};
    }

    render = () => {

        let { authenticated } = this.props.user;

        if (authenticated) {
            console.log('Redirecting to "/dashboard" from home');
            return (
                <Redirect to="/dashboard" />
            )

        } else {
            console.log('Redirecting to "/signin" from home');
            return (
                <Redirect to="/signin" />
            )

        }

    }
}

const mapStateToProps = (state) => {
    return {
        app: state.appReducer,
        user: state.userReducer
    }
}

const mapDispatchToProps = (dispatch) => {
    return {}
}

export default connect(mapStateToProps, mapDispatchToProps, null, { withRef: true })(Home);

unauthenticated.jsx

(对于仅在未经过身份验证时才可访问的路由)

import React from 'react';
import { connect } from 'react-redux';
import { Route, Redirect, withRouter } from 'react-router-dom';

class UnauthenticatedRoute extends React.Component {

    constructor(props) {
        super(props);
    }


    isSignedin = () => {
        return this.props.user.authenticated;
    }

    render = () => {

        let { component: Component, ...rest } = this.props;

        console.log('Unauthenticated:', !this.isSignedin() ? `Rendering` : `Redirecting`);

        return (

            <Route {...rest} render={(props) => (
                !this.isSignedin() ? (
                    <Component {...props} />
                ) : (
                        <Redirect to='/dashboard' />
                    )
            )} />

        )

    }

}

const mapStateToProps = (state) => {
    return {
        app: state.appReducer,
        user: state.userReducer
    }
}

const mapDispatchToProps = (dispatch) => {
    return {}
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps, null, { withRef: true })(UnauthenticatedRoute));

authenticated.jsx

(对于只有经过身份验证才能访问的路由)

import React from 'react';
import { connect } from 'react-redux';
import { Route, Redirect, withRouter } from 'react-router-dom';

class AuthenticatedRoute extends React.Component {

    constructor(props) {
        super(props);
    }

    isSignedin = () => {
        return this.props.user.authenticated;
    }

    render = () => {

        let { component: Component, ...rest } = this.props;

        console.log('Authenticated:', this.isSignedin() ? `Rendering` : `Redirecting`);

        return (

            <Route {...rest} render={(props) => (
                this.isSignedin() ? (
                    <Component {...props} />
                ) : (
                        <Redirect to='/signin' />
                    )
            )} />

        )

    }

}

const mapStateToProps = (state) => {
    return {
        app: state.appReducer,
        user: state.userReducer
    }
}

const mapDispatchToProps = (dispatch) => {
    return {}
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps, null, { withRef: true })(AuthenticatedRoute));

【问题讨论】:

  • PS:只有当我导航到“/”时才会出现问题。如果我导航到 /signin,则没有控制台错误。
  • 您确定没有将Authenticated和Unauthenticated的组件命名错误。请检查源代码和名称。如果可以,请告诉日志(console.logs),它会出现。
  • 唯一使用这两个的地方是在 routes.jsx 中。名称似乎没问题,因为唯一未经身份验证的路线是登录注册和重置。 '/' 路由是一个简单的路由组件。日志将描述中提到的错误打印 5 次
  • 还没有完成这方面的逻辑,但是如果isSignedIn() 在嵌套子级render()s 中调用总是失败,因为它不一定要更正this 上下文?将this.isSignedIn = this.isSignedIn.bind(this) 添加到适当的构造函数有帮助吗?
  • 它没有失败,因为它被声明为箭头函数,并且最新的 babel transpile 保留了上下文,因此您不需要再绑定 @AndyTaton

标签: reactjs redux react-router-v4 react-router-dom


【解决方案1】:

尝试将受保护的路由简化并分离为单个 RequireAuth 组件。在Redux 的帮助下,我们可以在用户通过身份验证后公开路由。

您也许可以使用 React 的 Context 提供程序,但无论哪种方式,您都需要使用某种可以将其状态/方法传递给子级的 HOC。否则,这将是 HOC 状态和方法来回传递的嵌套噩梦。

工作示例:https://codesandbox.io/s/88qmx06082(react-router v3——我使用和喜欢 v3 的原因之一,因为它超级容易嵌套路由)

工作示例:https://codesandbox.io/s/yqo75n896x (react-router v4)

routes/index.js (v4)

import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import Home from "../components/Home";
import Header from "../containers/Header";
import Info from "../components/Info";
import Sponsors from "../components/Sponsors";
import Signin from "../containers/Signin";
import RequireAuth from "../containers/RequireAuth";
import rootReducer from "../reducers";

const store = createStore(rootReducer);

export default () => (
  <Provider store={store}>
    <BrowserRouter>
      <div>
        <Header />
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/info" component={Info} />
          <Route path="/sponsors" component={Sponsors} />
          <Route path="/protected" component={RequireAuth} />
          <Route path="/signin" component={Signin} />
        </Switch>
      </div>
    </BrowserRouter>
  </Provider>
);

containers/RequireAuth.js (v4)

import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import ShowPlayerRoster from "../components/ShowPlayerRoster";
import ShowPlayerStats from "../components/ShowPlayerStats";
import Schedule from "../components/Schedule";

const RequireAuth = ({ match: { path }, isAuthenticated }) =>
  !isAuthenticated ? (
    <Redirect to="/signin" />
  ) : (
    <div>
      <Route exact path={`${path}/roster`} component={ShowPlayerRoster} />
      <Route path={`${path}/roster/:id`} component={ShowPlayerStats} />
      <Route path={`${path}/schedule`} component={Schedule} />
    </div>
  );

export default connect(state => ({
  isAuthenticated: state.auth.isAuthenticated
}))(RequireAuth);

【讨论】:

    【解决方案2】:

    解决方案如下,据我所知,这是一个逻辑问题。如果您想知道,没有安装多个组件。它与AuthenticatedRouteUnauthenticatedRoute 组件有关。我也完全删除了home 组件。

    验证渲染方法

    render = () => {
    
        let { component: Component, ...rest } = this.props;
    
        return (
    
            <Route {...rest} render={(props) => (
                this.isSignedin() ? (
                    <Component {...props} />
                ) : (
                        props.location.pathname === '/signin' ? (null) : (<Redirect to='/signin' />)
                    )
            )} />
    
        )
    
    }
    

    未经验证的渲染方法

    render = () => {
    
        let { component: Component, ...rest } = this.props;
    
        return (
    
            <Route {...rest} render={(props) => (
                !this.isSignedin() ? (
                    <Component {...props} />
                ) : (
                        props.location.pathname === '/' ? (null) : (<Redirect to='/' />)
                    )
            )} />
    
        )
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-20
      • 2020-08-13
      • 1970-01-01
      • 1970-01-01
      • 2020-12-11
      • 2017-08-21
      • 1970-01-01
      相关资源
      最近更新 更多