Invalid hook call. Hooks can only be called inside of the body of a function component
You can only call hooks from React functions. Read more here.
Just convert the Allowance
class component to a functional component.
Working CodeSandbox demo.
const Allowance = () => {
const [allowances, setAllowances] = useState([]);
useEffect(() => {
fetch("http://127.0.0.1:8000/allowances")
.then(data => {
return data.json();
})
.then(data => {
setAllowances(data);
})
.catch(err => {
console.log(123123);
});
}, []);
const classes = useStyles();
return ( <
Paper className = {
classes.root
} >
<
Table className = {
classes.table
} >
<
TableHead >
<
TableRow >
<
TableCell > Allow ID < /TableCell> <
TableCell align = "right" > Description < /TableCell> <
TableCell align = "right" > Allow Amount < /TableCell> <
TableCell align = "right" > AllowType < /TableCell> <
/TableRow> <
/TableHead> <
TableBody > {
allowances.map(row => ( <
TableRow key = {
row.id
} >
<
TableCell component = "th"
scope = "row" > {
row.AllowID
} <
/TableCell> <
TableCell align = "right" > {
row.AllowDesc
} < /TableCell> <
TableCell align = "right" > {
row.AllowAmt
} < /TableCell> <
TableCell align = "right" > {
row.AllowType
} < /TableCell> <
/TableRow>
))
} <
/TableBody> <
/Table> <
/Paper>
);
};
export default Allowance;
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body
Sir. I think you made a typo and the error is due to that.
Change useNavigate
to useNavigate()
import React, { useEffect, useState } from 'react'
import { Button, Container, Form } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import { Link, useLocation, useNavigate } from 'react-router-dom'
import { login } from '../actions/userAction'
import ErrorMessageBox from '../components/ErrorMessagebox'
import Loading from '../components/Loading'
export const SignInScreen = () => {
const navigate = useNavigate()
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const { search } = useLocation()
const redirectInUrl = new URLSearchParams(search).get('redirect')
const redirect = redirectInUrl ? redirectInUrl : '/'
const userLogin = useSelector((state) => state.userLogin)
const { userInfo, loading, error } = userLogin
const dispatch = useDispatch()
useEffect(() => {
if (userInfo) {
navigate(redirect)
}
}, [navigate, userInfo, redirect])
const submitHandler = (e) => {
e.preventDefault()
dispatch(login(email, password))
}
return (
<Container className="small-container">
<h1 className="my-3">Sign In</h1>
{error && <ErrorMessageBox variant="danger">{error}</ErrorMessageBox>}
{loading && <Loading />}
<Form onSubmit={submitHandler}>
<Form.Group className="mb-3" controlId="email">
<Form.Label>Email</Form.Label>
<Form.Control
type="email"
required
onChange={(e) => setEmail(e.target.value)}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="password">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
required
onChange={(e) => setPassword(e.target.value)}
/>
</Form.Group>
<div className="mb-3">
<Button type="submit">Sign In</Button>
</div>
<div className="mb-3">
New Customer?{' '}
<Link to={`/signup?redirect=${redirect}`}>Create new account</Link>
</div>
</Form>
</Container>
)
}
React call from class to functional component. Error: Invalid hook call. Hooks can only be called inside of the body of a function component
React hooks can only be called in function components or custom React hooks. In order to use the navigate
function you'll need to either create a wrapper component or a custom withNavigate
HOC to pass navigate
as a prop to your class component.
Wrapper
const MyComponentWithNavigation = props => {
const navigate = useNavigate();
return <MyClassComponent {...props} navigate={navigate} />;
};
Usage:
<Route path="..." element={<MyComponentWithNavigation />} />
HOC
const withNavigate = Component => props => {
const navigate = useNavigate();
return <Component {...props} navigate={navigate} />;
};
Usage:
const MyComponentWithNavigation = withNavigation(MyClassComponent);
...
<Route path="..." element={<MyComponentWithNavigation />} />
Accessing the navigate
function
In your class component, access navigate
from props.
this.props.navigate("/");
React 17.0.1: Invalid hook call. Hooks can only be called inside of the body of a function component
You're calling this loginForm
as if it was a plain function, not as a React component:
const loginForm = LoginForm({
onToken: token => {
const url = new URL(window.location.href);
const returnurl = url.searchParams.get('returnurl');
if (returnurl) {
window.location.href = decodeURIComponent(returnurl);
} else {
window.location.href = '/';
}
}
});
ReactDOM.render(loginForm, domContainer);
As a result, it doesn't get wrapped in React.createElement
, so it thinks the hook call is invalid.
Use JSX syntax instead:
const onToken = token => {
const url = new URL(window.location.href);
const returnurl = url.searchParams.get('returnurl');
if (returnurl) {
window.location.href = decodeURIComponent(returnurl);
} else {
window.location.href = '/';
}
}
ReactDOM.render(<LoginForm onToken={onToken} />, domContainer);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
React - Error: Invalid hook call. Hooks can only be called inside of the body of a function component. What is wrong my syntax?
when you call Logout
at onClick
you are calling hooks from your function Logout
outside of a component body, what's is not allowed.
You can abstract your Logout logic to a custom hook where it returns the logoutUser
function:
export default function useLogOut() {
const history = useHistory();
// we don't useEffect here, we are only interested in function logoutUser
const logoutUser = () => {
const response = axiosInstance.post('user/logout/blacklist/', {
refresh_token: localStorage.getItem('refresh_token'),
});
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
axiosInstance.defaults.headers['Authorization'] = null;
history.push('/login');
}
return { logoutUser }
};
then you consume your custom hook at your LoginUser
component body, extracting the logoutUser
method:
function LoginUser()
{
const user = useSelector(selectUser);
// use hook at component body extracting logoutUser method
const { logoutUser } = useLogOut();
const dispatch = useDispatch();
const handleLogout = (e) =>
{
if(e) e.preventDefault();
dispatch(logout());
};
const UserLoggedInAlert = () =>
{
return <Container>
<span>
You are already logged in!
</span>
<Button
component={NavLink}
variant="contained"
color="primary"
to="/logout"
// here now you can safely logout user since no hooks are being called
onClick={function(){ handleLogout(); logoutUser()}}
>
Do you want to logout?
</Button>
</Container>
};
return (
<Container>
{user ? <UserLoggedInAlert/> : <SignIn/> }
</Container>
);
}
export default LoginUser;
you can take a step ahead and simplify your LogOut
component:
export default function LogOut() {
const { logoutUser } = useLogOut();
useEffect(() => {
logoutUser()
});
return <div>Logout</div>;
};
Edit
for simplicity at your Logout.js do as:
export const useLogOut = () => {
const history = useHistory();
// we don't useEffect here, we are only interested in function logoutUser
const logoutUser = () => {
const response = axiosInstance.post('user/logout/blacklist/', {
refresh_token: localStorage.getItem('refresh_token'),
});
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
axiosInstance.defaults.headers['Authorization'] = null;
history.push('/login');
}
return { logoutUser }
};
export default function LogOut() {
const { logoutUser } = useLogOut();
useEffect(() => {
logoutUser()
});
return <div>Logout</div>;
};
at your your Login you import the hook with curly brackets:
import { useLogOut } from '../auth/Logout';
and at your index.js without the curly brackets you import the component:
import LogOut from './components/auth/Logout';
const routing = (
<Router>
<Route path="/logout" component={LogOut} />
</Router>
);
Related Topics
Nodejs Callbacks Simple Example
Cloud Firestore Case Insensitive Sorting Using Query
Get All Attributes of an Element Using Jquery
Chrome Extension - Sendresponse Not Waiting for Async Function
How to Get Selected HTML Text with JavaScript
What Is the Motivation for Bringing Symbols to Es6
Chrome, JavaScript, Window.Open in New Tab
How to Disable Text Selection Using Jquery
Idiomatically Find the Number of Occurrences a Given Value Has in an Array
Check If Event Exists on Element
Activexobject in Firefox or Chrome (Not Ie!)
How to Return Values from Async Functions Using Async-Await from Function
Object Method with Es6/Bluebird Promises
Selected Text Event Trigger in JavaScript