如何在调用 render 方法之前从 API 获取数据? (反应,护照,快递)

How do I fetch data from API before render method called? (react, passport, express)

我试图在允许用户访问特定路由之前验证用户是否已通过护照进行身份验证。为此,我需要访问我的 API,这将 return 我的用户的身份验证状态。但是,我希望在路由呈现之前进行调用,以便路由保持受保护。这是我目前的尝试:

import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';

class ProtectedRoute extends Component {
    constructor(){
        super()
        this.fetchAuthState().then(result => console.log('result',result))
        this.state = { 
            isAuth: false, 
            error: null
        }
    }
    async fetchAuthState() {
        try {
            const response = await fetch('http://localhost:3001/logincheck', {
              headers: {
                'content-type': 'application/json',
                accept: 'application/json',
              },
            });
            return await response.json();
          } catch (error) {
            console.error(error);
            this.setState({ error });
          }
      };

    render() {
      console.log('client check', this.state.isAuth)
      const { component: Component, ...props } = this.props
      return (
        <Route 
          {...props} 
          render={props => (
            this.state.isAuth ?
              <Component {...props} /> :
              <Redirect to='/login' />
          )} 
        />
      )
    }
  }

  export default ProtectedRoute; 

这是服务器端代码:

app.get('/logincheck', (req, res) =>{
  res.send(req.isAuthenticated())
})

我想因为react的生命周期,fetch应该在构造函数中调用,然后存储在state中。但是,当我尝试直接或在临时变量中存储结果时,获取结果显示未定义。我已经检查了 isAuthenticated() 的任何客户端形式的护照文档,但它似乎只适用于服务器端。我正在考虑实施一个 jwt 令牌系统,看看这是否是维护身份验证状态的更好方法,但我认为使用 api 路由进行检查会更容易。我是网络开发的新手,所以任何 advice/criticism 将不胜感激!

您可以添加一些加载屏幕,直到身份验证响应到达。

启动加载状态并在组件挂载上执行提取

class ProtectedRoute extends Component {
    constructor(){
        super()
        this.state = { 
            isAuth: false, 
            error: null,
            loading:true // default loading will be true
        }
    }
    componentDidMount(){
      this.fetchAuthState().then(result => this.setState({loading:false})) // after fetch end set loading false
    }
    ....
     render() {
      console.log('client check', this.state.isAuth)
      const { component: Component, ...props } = this.props
      return (
        {this.state.loading ? <LoadingComponent/> :<Route  
          {...props} 
          render={props => (
            this.state.isAuth ?
              <Component {...props} /> :
              <Redirect to='/login' />
          )} 
        />}
      )
    }
}

您可以通过添加一个额外的状态变量(例如 loading)来完成此操作,然后在 API returns 响应时切换它。但我会稍微重构您的代码,使其看起来像这样:

import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';

class ProtectedRoute extends Component {
    constructor(){
        super()
        this.state = {
            loading: true,
            isAuth: false, 
            error: null
        }
    }
    componentDidMount(){
        fetch('http://localhost:3001/logincheck', {
              headers: {
                'content-type': 'application/json',
                accept: 'application/json',
              },
            })
            .then(res => res.json())
            .then(json => {
              this.setState({isAuth: json.isAuth, loading: false})
            })
            .catch(e => console.log(e))
      }

    render() {
      console.log('client check', this.state.isAuth)
      const { component: Component, ...props } = this.props;
      const {loading, isAuth} = this.state;
      return (
        <Route 
          {...props} 
          render={() => {
            return loading ?
                <div>Loading...</div>
                :
                isAuth ?
                   this.props.children
                :
                    <Redirect to='/login' />
        }} />
      )
    }
  }

  export default ProtectedRoute;