Reputation: 333
Im trying to redirect my user when the user is logged in. but all my methods i found so far wont work. etg im trying to use useNavigate function using react router v6.
but for some reason i get the following error:
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See react-invalid-hook-call for tips about how to debug and fix this problem.
at:
/login.jsx:35
let navigate = useNavigate();
function:
PerformLogin = () => {
let navigate = useNavigate();
const username = this.state.username;
const password = this.state.password;
if (username === '') {
console.log("please enter username");
} else if (password === '') {
console.log("please enter password");
} else {
console.log("username of login: ",this.state.username);
axios.post(process.env.REACT_APP_DATAURL + `/login`,{ username: username, password: password },{withCredentials: true})
.then(res => {
res = res.data;
console.log(res);
console.log(res.data);
if (res.type) {
console.log("navigating logged in");
navigate.push('/crime');
//return <Navigate to="/crime" />;
}
})
}
}
Q: what do i have to do to fix this and be able to redirect my user?
Upvotes: 8
Views: 24247
Reputation: 1
*An example of how you can use.useHsitory has not been working properly in v6
import React from 'react';
import { createBrowserHistory } from 'history';
const StatusCodeCat: React.FC = () => {
// const history = useHistory();
const history = createBrowserHistory();
console.log(history);
return (
<div>
never
</div>
);
}
export default StatusCodeCat;
Upvotes: 0
Reputation: 511
In react-router-dom latest version(v6) you cannot use this.props.match.params.id
and this.props.history
(in react latest vesion history
replace with navigate
). Besides you cannot call them in class component. To call them in class component make a function first -
import { useParams, useNavigate } from "react-router-dom";
export function withParamsAndNavigate(Component) {
return (props) => (
<Component {...props} params={useParams()} navigate={useNavigate()} />
);
}
I want to use it for ProductDetails
component. That's given below -
import { withParamsAndNavigate } from "./getParamsAndNavigate.js";
class ProductDetails extends React.Component {
state = {//}
render() {
const{params,navigate} = this.props;
// params.id - will return the id,
// navigate('yourUrl') - will redirect the target url.
return (
//
);
}
}
export default withParamsAndNavigate(ProductDetails);
Here is my App
module where I defined my routes -
import React from "react";
import { Routes, Route} from "react-router-dom";
import Product from "./components/Product";
import ProductDetails "./components/ProductDetails";
function App() {
return (
<div>
<main role='main' className='container'>
<Routes>
<Route path='/product' element={<Product />} />
<Route path="/product/:id"} element={<ProductDetails />} />
</Routes>
</main>
</div>
);
}
export default App;
It works for me and hope it will help you.
Upvotes: 1
Reputation: 3711
In react-router v6 there is no withRouter
nor useHistory
. I would recommend to refactor your component to use hooks for the sake of simplicity, but an alternative solution is to create a wrapper component that will pass the navigate function obtained from the hook as a prop:
import { useNavigate } from 'react-router-dom';
class MyComponent extends React.Component {
//...
PerformLogin = () => {
const username = this.state.username;
const password = this.state.password;
// ...
this.props.navigate('/crime');
}
}
function WithNavigate(props) {
let navigate = useNavigate();
return <MyComponent {...props} navigate={navigate} />
}
export default WithNavigate
useHistory
is a hook and hooks can only be used inside "function" components.
However I can guess you are using it from a "class" component, since there are some this.state
, so you cannot use the hook there.
Another approach that should work for you would be to wrap your component inside a withRouter
:
import { withRouter } from "react-router";
class MyComponent extends React.Component {
//...
PerformLogin = () => {
const history = this.props.history;
const username = this.state.username;
const password = this.state.password;
// ...
}
}
export default withRouter(MyComponent)
The withRouter will inject the history as a prop.
Upvotes: 28
Reputation: 3784
You can only call hooks at the top level (https://reactjs.org/docs/hooks-rules.html) inside a component.
Therefore, this is invalid, being it's not only in an if statement, in a promise's .then
function, and also does not appear to even be a functional component, rather, just a function:
if (res.type) {
console.log("navigating logged in");
navigate.push('/crime');
//return <Navigate to="/crime" />;
}
I would instead attempt doing something like setting a flag, and then navigating based upon that flag:
PerformLogin = () => {
let navigate = useNavigate();
let shouldNavigate = false;
const username = this.state.username;
const password = this.state.password;
if (username === '') {
console.log("please enter username");
} else if (password === '') {
console.log("please enter password");
} else {
console.log("username of login: ",this.state.username);
axios.post(process.env.REACT_APP_DATAURL + `/login`,{ username: username, password: password },{withCredentials: true})
.then(res => {
res = res.data;
console.log(res);
console.log(res.data);
if (res.type) {
console.log("navigating logged in");
shouldNavigate = true;
//return <Navigate to="/crime" />;
}
})
}
navigate.push(shouldNavigate ? '/crime' : currentURL);
}
But I would avoid this altogether and simply utilize the useHistory hook to get an instance of history and work on that (I haven't tested this either but it should work):
PerformLogin = () => {
const history = useHistory();
const username = this.state.username;
const password = this.state.password;
if (username === '') {
console.log("please enter username");
} else if (password === '') {
console.log("please enter password");
} else {
console.log("username of login: ",this.state.username);
axios.post(process.env.REACT_APP_DATAURL + `/login`,{ username: username, password: password },{withCredentials: true})
.then(res => {
res = res.data;
console.log(res);
console.log(res.data);
if (res.type) {
console.log("navigating logged in");
history.push('/crime');
//return <Navigate to="/crime" />;
}
})
}
}
Note: You have to do this directly in your component itself, you can't use hooks in a normal function that isn't a component.
Upvotes: 0