异步在 React 功能组件中抛出错误

Async throws error in React Functional Component

我尝试在以下功能组件中使用 use async 但抛出错误

const RouteConfig =  async ({ component: Component, fullLayout, user, auth, ...rest}) => (

  <Route
    {...rest} 
    render={props => {
      
      return (
        <ContextLayout.Consumer>
          {context => {
            let LayoutTag =
              fullLayout === true
                ? context.fullLayout
                : context.state.activeLayout === 'horizontal'
                ? context.horizontalLayout
                : context.VerticalLayout
                const verified = await verifyToken(auth.values)
            return  (auth.values !== undefined && auth.values.isSignedIn && verified) ? (
              <LayoutTag {...props} permission='{user}'>
                <Suspense fallback={<Spinner />}>
                  <Component {...props}></Component>
                </Suspense>
              </LayoutTag>
            ) : (
              <context.fullLayout {...props} permission={user}>
                <Suspense fallback={<Spinner />}>
                  <Login {...props} />
                </Suspense>
              </context.fullLayout>
            )
          }}
        </ContextLayout.Consumer>
      )
    }}
  />
)
const mapStateToProps = state => {
  return {
    user: state.auth.login.userRole,
    auth: state.auth.login
  }
}

const AppRoute = connect(mapStateToProps)(RouteConfig)

下面是 verifyToken 函数 return true or false

const verifyToken = async props => {
    if (props.accessToken !== undefined) {
    //if (props !== undefined) {
        if (assertAlive(jwt.decode(props.accessToken))) {
            const verified = await refreshToken(props)
            console.log(verified)
            if (verified){
                console.log('Authorized')
                return true
            } else {
                console.log('Unauthorized')
                return false
            }
        } else {
            return false
        }
    }else 
        return false
}

function assertAlive (decoded) {
    const now = Date.now().valueOf() / 1000
    if (typeof decoded.exp !== 'undefined' && decoded.exp < now) {
      //throw new Error(`token expired: ${JSON.stringify(decoded)}`)
      return false
    }
    if (typeof decoded.nbf !== 'undefined' && decoded.nbf > now) {
      //throw new Error(`token not yet valid: ${JSON.stringify(decoded)}`)
      return false
    }
    return true
  }

上面使用的 refreshToken 有一个函数,它从 API 调用

获得响应
export const  refreshToken =  async  () => {
  const options = { withCredentials: true };
  const resp = await axios.post('http://localhost:4000/api/auth/verifyToken',{}, options).catch(err => {console.log(err); return false;});
  //console.log(resp.status)
    if (resp.status === 200){
      //console.log('200 passed')
      return true
    }else if (resp.status === 401){
      //console.log('401 failed')
      return false
    }else{
      //console.log('204 failed')
      return false
    }
}

如有解决此问题的任何建议,我们将不胜感激。如果有人有更好的编码方式,请告诉我。我对 ReactJS 有点陌生,欢迎提出建议。如果 Token 被授权,则第一个函数用于检查每个路由。如果它被授权,它允许访问页面,如果没有则重定向到登录页面。

根据@Mordechai 的建议,我进行了以下更改,但出现错误

./src/Router.js Line 193:40: React Hook "useState" is called in function "verified" which is neither a React function component or a custom React Hook function react-hooks/rules-of-hooks Line 194:3: React Hook "useEffect" is called in function "verified" which is neither a React function component or a custom React Hook function react-hooks/rules-of-hooks

function verified(auth){
  const [verified, setVerifiedValue] = useState(verifyToken(auth.values));
  useEffect(() => { setVerifiedValue(verifyToken(auth.values) )})
  return verified;
}

const RouteConfig =  ({ component: Component, fullLayout, user, auth, ...rest}) => (

  <Route
    {...rest} 
    render={props => {
      
      //useEffect(() => {const verified = verifyToken(auth.values) });
      return (
        <ContextLayout.Consumer>
          {context => {
            let LayoutTag =
              fullLayout === true
                ? context.fullLayout
                : context.state.activeLayout === 'horizontal'
                ? context.horizontalLayout
                : context.VerticalLayout
                console.log(VerifiedToken)
            return  (auth.values !== undefined && auth.values.isSignedIn && VerifiedToken) ? (
              <LayoutTag {...props} permission='{user}'>
                <Suspense fallback={<Spinner />}>
                  <Component {...props}></Component>
                </Suspense>
              </LayoutTag>
            ) : (
              <context.fullLayout {...props} permission={user}>
                <Suspense fallback={<Spinner />}>
                  <Login {...props} />
                </Suspense>
              </context.fullLayout>
            )
          }}
        </ContextLayout.Consumer>
      )
    }}
  />
)
const mapStateToProps = state => {
  return {
    user: state.auth.login.userRole,
    auth: state.auth.login
  }
}

const AppRoute = connect(mapStateToProps)(RouteConfig)
const VerifiedToken = connect(mapStateToProps)(verified)

以下是否有效?

const NONE = {};
const RouteConfig = ({
  component: Component,
  fullLayout,
  user,
  auth,
  ...rest
}) => (
  <Route
    {...rest}
    render={(props) => {
      const [verified, setVerified] = React.useState(NONE);
      React.useEffect(
        () => verifyToken(auth.values).then(setVerified),
        []
      );
      if (verified === NONE) {
        return null;
      }
      return (
        <ContextLayout.Consumer>
          {(context) => {
            let LayoutTag =
              fullLayout === true
                ? context.fullLayout
                : context.state.activeLayout ===
                  'horizontal'
                ? context.horizontalLayout
                : context.VerticalLayout;
            return auth.values !== undefined &&
              auth.values.isSignedIn &&
              verified ? (
              <LayoutTag {...props} permission="{user}">
                <Suspense fallback={<Spinner />}>
                  <Component {...props}></Component>
                </Suspense>
              </LayoutTag>
            ) : (
              <context.fullLayout
                {...props}
                permission={user}
              >
                <Suspense fallback={<Spinner />}>
                  <Login {...props} />
                </Suspense>
              </context.fullLayout>
            );
          }}
        </ContextLayout.Consumer>
      );
    }}
  />
);

挂钩必须命名为 useXxx 否则 eslint 会报错。此外,必须在功能组件的顶层调用挂钩。

您在 useState() 默认值参数和效果中都调用了 verifyToken()。如果这是一个漫长的过程,你应该只在效果上做。

如果你想在组件的生命周期中只调用useVerify()中的verifyToken()一次,你应该在useEffect()依赖数组

中添加一个空数组
function useVerified(auth){
  const [verified, setVerifiedValue] = useState();
  useEffect(() => {
    const doVerify = async () => {
      setVerifiedValue(await verifyToken(auth.values))
    }
    doVerify()
  }, [])
  return verified;
}

const RouteConfig =  ({ component: Component, fullLayout, user, auth, ...rest}) => {

  const verified = useVerified(auth);

  return <Route
    {...rest} 
    render={props => {
      return (
        <ContextLayout.Consumer>
          {context => {
            let LayoutTag =
              fullLayout === true
                ? context.fullLayout
                : context.state.activeLayout === 'horizontal'
                ? context.horizontalLayout
                : context.VerticalLayout
                console.log(VerifiedToken)
            return  (auth.values !== undefined && auth.values.isSignedIn && VerifiedToken) ? (
              <LayoutTag {...props} permission='{user}'>
                <Suspense fallback={<Spinner />}>
                  <Component {...props}></Component>
                </Suspense>
              </LayoutTag>
            ) : (
              <context.fullLayout {...props} permission={user}>
                <Suspense fallback={<Spinner />}>
                  <Login {...props} />
                </Suspense>
              </context.fullLayout>
            )
          }}
        </ContextLayout.Consumer>
      )
    }}
  />
}
const mapStateToProps = state => {
  return {
    user: state.auth.login.userRole,
    auth: state.auth.login
  }
}

const AppRoute = connect(mapStateToProps)(RouteConfig)
const VerifiedToken = connect(mapStateToProps)(verified)