React is complaining about code below, saying it useEffect is being called conditionally:
import React, { useEffect, useState } from 'react'
import VerifiedUserOutlined from '@material-ui/icons/VerifiedUserOutlined'
import withStyles from '@material-ui/core/styles/withStyles'
import firebase from '../firebase'
import { withRouter } from 'react-router-dom'
function Dashboard(props) {
const { classes } = props
const [quote, setQuote] = useState('')
if(!firebase.getCurrentUsername()) {
// not logged in
alert('Please login first')
props.history.replace('/login')
return null
}
useEffect(() => {
firebase.getCurrentUserQuote().then(setQuote)
})
return (
<main>
// some code here
</main>
)
async function logout() {
await firebase.logout()
props.history.push('/')
}
}
export default withRouter(withStyles(styles)(Dashboard))
And that returns me the error:
React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.
Does anyone happen to know what the problem here is?
Your code, after an if statement that contains return, is equivalent to an else branch:
if(!firebase.getCurrentUsername()) {
...
return null
} else {
useEffect(...)
...
}
Which means that it's executed conditionally (only when the return is NOT executed).
To fix:
useEffect(() => {
if(firebase.getCurrentUsername()) {
firebase.getCurrentUserQuote().then(setQuote)
}
}, [firebase.getCurrentUsername(), firebase.getCurrentUserQuote()])
if(!firebase.getCurrentUsername()) {
...
return null
}
Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function. You can follow the documentation here.
I couldn't find the use case in the above code. If you need the effect to run when the return value of firebase.getCurrentUsername() changes, you might want to use it outside the if condition like:
useEffect(() => {
firebase.getCurrentUserQuote().then(setQuote)
}, [firebase.getCurrentUsername()]);
I had a similar problem with the same error message, where the order of variable declarations was the source of the error:
if (loading) return <>loading...</>;
if (error) return <>Error! {error.message}</>;
const [reload, setReload] = useState(false);
const [reload, setReload] = useState(false);
if (loading) return <>loading...</>;
if (error) return <>Error! {error.message}</>;
The hook needs to be created before potential conditional return blocks