【问题标题】:React Router *Not Found* rendered first before main routesReact Router *Not Found* 在主路由之前首先渲染
【发布时间】:2017-08-18 13:33:24
【问题描述】:

我正在从事一个大型项目,我有一个授权系统,登录用户可以访问某些路线,而 Not Found 组件在 Logged 上提供服务出用户。问题是,当用户被标记为已登录并拥有有效令牌然后进入页面(例如 /account)时,组件 Not Found 首先呈现,然后组件 account 被正确呈现。

我有一个异步 componentDidMount,我在其中验证我的令牌,如果它有效,我设置 isLogged: true 的状态。同样在我的交换机中的每条路由上,我都在检查 isLogged 的状态,然后才发送相应的组件。

我的异步组件DidMount

{/* Username is from localstorage */}

async componentDidMount() {
  if ((USERNAME != "") && (USERNAME != null)) {
    const logged = await checkTheToken({'Username': USERNAME}).then((result) => {
      if(result.status == 202) {
         this.setState({isLogged: true});
         this.setState({checking: false});
      };
    });
  }
}

这是路由器(*假设我们正在尝试访问 /user 页面。注意我使用 react-router, react-router-dom ^4.1.1* )

   if (this.state.checking) {
        return null;
   } else {
   return ( 
     <Router>
        <Switch>
            {/* This is Not Rendered First and Not Found rendered before FALSLY */}

            {this.state.isLogged && <Route exact path="/user" component={() => (<User isLogged={this.state.isLogged} username={USERNAME} />)} />}

            {/* This is Rendered First and Not Found is not rendering at all CORRECTLY */}

            <Route exact path="/test" component={() => (<Test isLogged={this.state.isLogged} />)} />

            <Route component={() => (<NotFound isLogged={this.state.isLogged} />)} />
        </Switch>
     </Router>
   );

我认为问题出在 {this.state.isLogged && ...} 因为如果我们尝试访问 /test 组件会正确呈现而没有 未找到先渲染。

另外,我测试了所有的生命周期方法

【问题讨论】:

  • 您是否尝试过在componentWillMount 中进行身份验证检查,您的组件在到达componentDidMount 之前已经渲染。
  • 我测试了所有的生命周期方法
  • 您可能需要添加一个像checking 这样默认为true 的状态字段。当您得到响应时,将成功或错误设置为 checkingfalse。在你的渲染if(this.state.checking) return null;.
  • 我已根据您的评论更新了我的问题。现在根本不渲染主页
  • Home 是什么?您需要将this.state({checking: .. 移到if(result.status...) 之外,并且如果请求有错误,您还需要将其放在您捕获的位置。因为无论您的身份验证检查的响应如何,checking 都需要设置为 false。如果您没有收到任何错误并且它肯定会设置状态,那么代码看起来很好。我认为您不需要在 componentDidMount 函数上使用 async/await,因为我们正在使用状态来管理您的身份验证检查的异步性质。

标签: reactjs react-router


【解决方案1】:

我认为你是对的,问题来自{this.state.isLogged &amp;&amp; ...}

让我们一步一步来。

第一个 this.state.isLogged 是假的。这确实意味着 &lt;User isLogged={this.state.isLogged} username={USERNAME} /&gt; 当前不在 ReactRouter 配置中。

我们可以猜测 ReactRouter 将匹配默认组件 (&lt;Route component={() =&gt; (&lt;NotFound isLogged={this.state.isLogged} /&gt;)} /&gt;),因为 /user 不在其配置中。

那么实际行为是正确的。

实现目标的最快方法是将令牌检查移动到您的子组件中,如下所示:

async componentDidMount() {
  if ((USERNAME != "") && (USERNAME != null)) {
    const logged = await checkTheToken({'Username': USERNAME}).then((result) => {
      if(result.status !== 202) {
        history.push('/not-found')
      } else {
        this.setState({isLogged: true});
        this.setState({checking: false});
      };
    });
  }
}

渲染函数是这样的:

render () {
 if(!this.state.isLogged) return <span />
 return <div>...</div>
}

这种方法的主要问题是它需要所有经过身份验证的组件来实现它。

您还需要将代码分解为服务以避免多次调用。

第二种方法是将其分解为一个代理组件,像这样进行检查:

<Router>
    <Switch>
        <Route component={Authenticated}>
           <Route exact path="/user" component={() => (<User isLogged={this.state.isLogged} username={USERNAME} />)} />
        </Route>
        <Route exact path="/test" component={() => (<Test isLogged={this.state.isLogged} />)} />
        <Route component={() => (<NotFound isLogged={this.state.isLogged} />)} />
    </Switch>
 </Router>

这个组件现在将成为进行令牌检查的组件。

渲染函数如下所示:

render () {
 if(!this.state.isLogged) return <span />
 return {this.props.children}
}

这里的主要问题是您无法在组件之间轻松共享“this.state.isLogged”

如果你想使用一些全局状态共享和更新多个组件,我强烈建议你看看Redux

由于 redux 的学习曲线很难,如果你只需要共享这个单一的值,你可以尝试一些使用 observable 模式的东西。 (例如:observable serviceobservable service + connector

我所有的代码示例都没有经过测试,在这里可以引导您朝着正确的方向前进。在我看来,有很多方法可以归档你想要的东西,遗憾的是我只能告诉你为什么它目前不起作用,我希望我给你足够的线索来找到适合你用例的解决方案。

【讨论】:

  • 感谢您的回答!我在每个相应的组件上移动了 checkToken。因此,ComponentDidMount 上的每个组件都必须检查 isLogged 用户。我不认为这是否经过优化(可能不是),但它可以工作。我更喜欢在加载组件时避免多次调用 db,并且我更喜欢通过 props 将值从一个组件传递到另一个组件,但我认为这是唯一的方法。关于第二种方法,我有反应路由器 v4,我无法在我的路由器上添加嵌套路由。我试图降级路由器,但收到多个错误,如果您想更新问题,请告诉我
  • 正如你所说,我必须将代码分解为服务。我会检查的。
  • 第二个例子是关于如何为您的服务创建连接器jsfiddle.net/qcdmuzac/2
猜你喜欢
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 2018-01-06
  • 2018-10-18
  • 2017-06-07
  • 2017-11-15
  • 2019-03-13
相关资源
最近更新 更多