异步在 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)
我尝试在以下功能组件中使用 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)