使用 React Router 时无法访问 App 组件

Posted

技术标签:

【中文标题】使用 React Router 时无法访问 App 组件【英文标题】:Unable to access App component when using React Router 【发布时间】:2020-02-05 06:57:50 【问题描述】:

我正在尝试使我的应用程序更受路线驱动/控制。我正在使用React Router 和一个外部路由文件,以便从我的组件中抽象出路由逻辑。除 App 组件本身外,其他路由和组件均正常工作。我实际上是在尝试将所有其他路由包装在根路由('/')下,其组件是App.js

下面是我的routes/index.js 文件。

import React from "react";
import PropTypes from "prop-types";
import  Router, Route, Redirect   from "react-router";

import App from "../App.js";
import Home from "../components/Home/Home";
import Games from "../components/Games/containers/Games";
import LoginSignUp from "../components/LoginSignUp/LoginSignUp";
import NotFound from "../components/NotFound/NotFound";
import Account from "../components/Account/Account";
import Trivia from "../components/Trivia/Trivia";
import store from '../config/store';

const getGame = (nextState, replace, callback) => 
    var userGames = store.getState().auth.user.games;
    if (userGames.includes(parseInt(nextState.match.params.id)))
        return <Trivia/>
     else 
        return <Redirect to="/404"/>
   
;

const Routes = ( history, store ) => 

    return (
         <Router history=history store=store>
            <Route path="/" component=App>
                <Route exact path="/404" component=NotFound />
                <Route exact path="/give/different/path" component=Home/>
                <Route exact path="/games" component=Games/>
                <Route path="/account" component=Account/>
                <Route path="/games/:id" render=getGame/>
                <Route path='/login' component=LoginSignUp/>
            </Route>
        </Router>
    );
;

Routes.propTypes = 
    history: PropTypes.object.isRequired,
    store: PropTypes.object.isRequired
;

export default Routes;

我也试过这个没有&lt;Route exact path="/" component=Home/&gt; 的路由设置,我试过使用&lt;Route exact path="/" component=App&gt; 无济于事。

下面是我的App.js 组件。

import React from 'react';
import Header from './components/Header/Header.js';
import './App.css';
import createAction from "redux-actions";
import connect from "react-redux";

class App extends React.Component 

    state = 
        loggedIn: true
    

    render()
         debugger
         return (
             <div className="App">
                 <Header loggedIn=this.state.loggedIn user=this.props.user/>
             </div>
         );
     
 

 const mapStateToProps = (games, auth) => 
    return
        user: auth.user,
        games: games.games
    
 ;

 const mapDispatchToProps = dispatch => 
    return 
        getGame(obj) 
            const actionCreator = createAction(
                "games/getGame"
            );
            const action = actionCreator(obj);
            dispatch(action);
        
    
;

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(App);

这是我的相关依赖项及其版本。

"react-router": "^5.1.2",
"react-router-dom": "^5.1.0",
"react-router-redux": "^4.0.8",

【问题讨论】:

【参考方案1】:

它不会那样工作,看看你有一个路径/ 对应App 然后/ 对应Home,它无法正确匹配。请查看 React Router 文档。这是nested routes 示例的链接。

为了让你去某个地方看看这个对你的路由器的修改 你有:

            <Route path="/" component=App>
                <Route exact path="/404" component=NotFound />
                <Route exact path="/" component=Home/>
                <Route exact path="/games" component=Games/>
                <Route path="/account" component=Account/>
                <Route path="/games/:id" render=getGame/>
                <Route path='/login' component=LoginSignUp/>
            </Route>

但效果会更好

            <Route exact path="/" component=App />
            <Route exact path="/home" component=Home/>
            <Route exact path="/account" component=Account/>
            <Route exact path="/games" component=Games/>
            <Route exact path="/games/:id" render=getGame/>
            <Route exact path='/login' component=LoginSignUp/>
            <Route component=NotFound />

【讨论】:

感谢您的回复。我可以点击 App 组件,但我收到一条错误消息 You should not use &lt;Link&gt; outside a &lt;Router&gt;,我假设它来自我的导航组件,它位于 App.js 中,但由于 App 本身被包裹在 &lt;Router&gt; 中,它不会感觉它的子组件(以及任何后续链接)也将被包裹在 &lt;Router&gt;? 应该,如果您查看链接,您会发现确实如此。看起来它是在文档中完成的。 我查看了链接,它很有帮助。从技术上讲,我的&lt;Link/&gt; 位于&lt;Header/&gt; 组件中,但仅在&lt;App/&gt; 中导入,其他任何地方都没有。就像&lt;App/&gt;&lt;Header/&gt; 之前被点击。除非&lt;Link/&gt; 必须在&lt;App/&gt; 中,而不是&lt;App/&gt; 的孩子。 有什么方法可以使用路由将其他组件包装在&lt;App/&gt; 中?我希望&lt;App/&gt; 中的&lt;Header/&gt; 出现在所有页面上,我可以通过使App 的路径包含(不是确切路径)来做到这一点,但这会产生一个问题,即URL 可以是/not-valid-url然后它将呈现&lt;Header/&gt; 和一个空白页。【参考方案2】:

我认为您应该以这种方式更改您的代码。 并在导入时检查应用组件的路径

<Router history=history store=store>
  <Switch>
    <Route path="/" component=App />
    <Route exact path="/404" component=NotFound />
    <Route exact path="/home" component=Home />
    <Route exact path="/games" component=Games />
    <Route path="/account" component=Account />
    <Route path="/games/:id" render=getGame />
    <Route path="/login" component=LoginSignUp />
  </Switch>
</Router>;

【讨论】:

感谢您的回复。我尝试过这种方式,但我得到一个错误,说 You should not use &lt;Link&gt; outside a &lt;Router&gt; 我假设它来自我的导航组件,它位于 App.js 但由于 App 本身被包裹在 &lt;Router&gt;组件(以及任何后续链接)也将包含在 &lt;Router&gt;?另外,将exact path 用于Homepath 用于App 有什么意义? ***.com/questions/49162311/…检查一下 是的,如果您的 &lt;Link/&gt; 在应用程序组件中,那么它应该可以工作 从技术上讲,它在 &lt;Header/&gt; 组件中,但仅在 &lt;App/&gt; 中导入,其他任何地方都没有。就像&lt;App/&gt;&lt;Header/&gt; 之前被点击。除非 &lt;Link/&gt; 必须在 &lt;App/&gt; 中,而不是 &lt;App/&gt; 的子级。 开关不维护App 与子组件,它似乎只显示App。当我取下开关时,效果更好。【参考方案3】:

借助其他答案提供的见解,我能够想出一个解决方案来满足我的所有需求。

这是我更新的文件。第一个是我的根index 文件。作为预防措施,我用this issue's answer 建议的import BrowserRouter as Router from 'react-router-dom' 替换了所有import Router from 'react-router' 实例。将所有react-router 实例替换为react-router-dom 有助于阻止You should not use &lt;Switch&gt; outside a &lt;Router&gt;You should not use &lt;Route&gt; outside a &lt;Router&gt; 错误。

    <Provider store=store>
        <Router history=browserHistory store=store>
            <App/>
        </Router>
    </Provider>

我的路线/索引。

const Routes = ( history, store ) => 

    return (
            <Switch>
                <Route exact path="/" component=Home />
                <Route exact path="/404" component=NotFound />
                <Route exact path="/games" component=Games />
                <Route exact path="/account" render=accountDetails/>
                <Route path="/games/:id" render=getGame />
                <Route exact path="/login" component=LoginSignUp />
                <Redirect to='404' />
            </Switch>
    );
;

App 现在包括以下内容。

import Routes from './routes/index.js';

class App extends React.Component 

    state = 
        loggedIn: true
    ;

    render()
        return (
            <div className="App">
                <Header/>
                <Routes/>
            </div>
        );
    

首先,我决定从routes/index 中删除App。我的原始路由层次结构基于另一个未使用react-router 4 的项目。这就是为什么在另一个项目中,App 路由下的嵌套路由实现了我想要的。在react router 4this was not possible 中,因此出现Cannot use Link outside of Router 错误。因此,我将App 包装在我的根索引文件中的Router 中,然后将所有其他路由包装在我的routes/index 文件中的Switch 中,并将它们导入AppApp 现在可以将路由器用于Header 组件以及包裹在Switch 中的其他路由。

这也解决了我不得不为App 牺牲exact path 的问题。因为我想在每一页上使用Header,所以我希望App 出现在每一页上。使用exact path 阻止了我这样做。它还阻止我使用“/”来渲染Home。当我将Appexact path 设置为path 时,我能够做到这一点,但是可以放入任何随机未声明的路线。例如,localhost:3000/poop 不会像我预期的那样呈现NotFound,它只会渲染什么。

总之,通过将App 移出routes/index,我可以将其目录包装在根索引文件中的Router 中。然后通过将Routes 导入App,我可以让我的应用程序更受路由驱动,同时在所有页面上保持Header。此外,通过将我的所有路由包装在Switch 中并将根路径设为exact path,我可以正确处理未知路径并使用&lt;Redirect to='404' /&gt; 渲染NotFound 组件。

【讨论】:

以上是关于使用 React Router 时无法访问 App 组件的主要内容,如果未能解决你的问题,请参考以下文章

react-router-dom 无法按预期使用路由

当路由匹配时,React Router 不显示组件(但渲染工作)

React Router 使用教程

使用 create-react-app 将 react-router-dom 添加到 react 应用程序时,为啥玩笑测试会中断

如何正确使用 react-router-dom 中的 useHistory()?

React Router 无法渲染路由