How to change the URL without using <Link> component? - reactjs

In react, one can use the <Link> component to change the URL when the user clicks on the <Link>.
However, this is not what I want.
I need to change the URL when a useState value changes. So I need to change the URL inside of a useEffect.
How can this be done?

You can use the useHistory hook provided with react-router-dom.
import { useHistory } from "react-router-dom";
function HomeButton() {
let history = useHistory();
function handleClick() {
history.push("/home");
}
return (
<button type="button" onClick={handleClick}>
Go home
</button>
);
}

If you want to use dynamic URL use can use below approach
const [link, setLink] = useState('/profile');
useEffect(() => {
// logic
setLink('/logout');
}, [state you want]);
return (
<div>
<Link to={link} />
</div>
);
or you want to go to a URL after some logic
const history = useHistory();
useEffect(() => {
// logic
history.push('/profile');
}, [some state])
To use useHistory you want import like import { useHistory } from "react-router-dom";

Related

React-router : conditionally redirect at render time

So I have this basic component <Redirectable />:
import React from 'react';
import {
useParams,
useHistory,
Redirect,
} from 'react-router-dom';
export default () => {
const history = useHistory();
const {id} = useParams();
if (!checkMyId(id) {
// invalid ID, go back home
history.push('/');
}
return <p>Hey {id}</p>
}
But I get the following error:
Warning: Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.
I also tried: <Redirect push to="/" />, but same error.
What's the correct way to handle this? I read about onEnter callback at <Router /> level, but as far as I'm concerned, the check should happen at <Redirectable /> level.
There should be a solution, shouldn't it? I don't feel like I'm doing something completely anti-react-pattern, am I?
This seems to do the trick. I was not able to find any documentation as to why this occures. All I was able to find was different examples with callbacks but this solved it for me.
import React from 'react';
import {
useParams,
useHistory,
Redirect,
} from 'react-router-dom';
const MyComponent = () => {
const history = useHistory();
const {id} = useParams();
if (!checkMyId(id) {
// invalid ID, go back home
history.push('/');
}
return <p>Hey {id}</p>
}
export default MyComponent;
It seems that react may recognize export default () => { as a pure component and so side effects are prohibited.
Yes, it seems to me you are written the component in a anti pattern way. Can you please update like below:
const Rediractabke = () => {
const history = useHistory();
const {id} = useParams();
if (!checkMyId(id) {
// invalid ID, go back home
history.push('/');
}
return <p>Hey {id}</p>
}
export default as Redirectable;
#c0m1t was right, the solution was to use useEffect:
import React, {useEffect} from 'react';
import {
useParams,
useHistory,
Redirect,
} from 'react-router-dom';
export default () => {
const history = useHistory();
const {id} = useParams();
useEffect(() => {
if (!checkMyId(id) {
// invalid ID, go back home
history.push('/');
}
})
return <p>Hey {id}</p>
}

this.props.history.push is undefined

I am creating a form with some predefined values, and i want to route to the dashboard page once the form is submitted. I am using handleLoginSubmit func on the onsubmit of the form. For that, I have the following code:
handleLoginSubmit = (e) => {
e.preventDefault();
let hardcodedCred = {
email: "email#email.com",
password: "password123",
};
if (
this.state.email == hardcodedCred.email &&
this.state.password == hardcodedCred.password
) {
//combination is good. Log them in.
//this token can be anything. You can use random.org to generate a random string;
// const token = "123456abcdef";
// sessionStorage.setItem("auth-token", token);
//go to www.website.com/todo
// history.push("/dashboard");
this.props.history.push("/dashboard");
// console.log(this.state.route);
console.log(this.context);
console.log("logged in");
// <Link to={location} />;
} else {
//bad combination
alert("wrong email or password combination");
}
};
But, I am receiving the error saying that history is undefined.
Please help me out here
You need to export the component with router to access history
import { withRouter } from 'react-router-dom';
export default withRouter(ComponentName)
if your component is linked with Route then you can directly access that in this.props but if its sub-component or children of some component then you cant access it into this.props.
so there is multiple way to solve it
pass history as props in your component if that component is linked with Route
<Component history={this.props.history} />
use withRouter HOC, that bind all Route props in your component
import { withRouter } from 'react-router-dom';
export default withRouter(Component)
use useHistory hook and save it to constant ( functional component )
import { useHistory } from 'react-router-dom';
const history = useHistory();
Update of Nisharg Shah's answers of part 3 for future reference.
If you are using react-router-dom v6, then use useNavigate instead of useHistory.
You can use:
import { useNavigate } from "react-router-dom";
let navigate = useNavigate();
OR
import { useNavigate } from "react-router-dom";
function App() {
let navigate = useNavigate();
function handleClick() {
navigate("/home");
}
return (
<div>
<button onClick={handleClick}>go home</button>
</div>
);
}

How to write logout function in functional component using reactjs?

I'm new in creating functional components, in Class Components we declare logout function in this
logout = () => {
sessionStorage.setItem("userToken", '');
sessionStorage.clear();
this.setState({ redirect: true });
}
format but i don't know how to declare variable and how to write push to another functional component.
Can anyone please help me in this query?
React Router v4 has now added the useHistory hook for stateless / functional components. Sample snippet that would handle logout in your case
import { useHistory } from "react-router-dom";
function Logout() {
let history = useHistory();
function handleLogOut() {
sessionStorage.setItem("userToken", '');
sessionStorage.clear();
history.push("/sigin"); // whichever component you want it to route to
}
return (
<button type="button" onClick={handleLogOut}>
Go home
</button>
);
}
Apart from the answer provided by #sv12, you can also use history module.
import { createBrowserHistory } from 'history';
export const history = createBrowserHistory();

How to send params in useHistory of React Router Dom?

I am using React Router hooks for navigation useHistory.
Navigate : history.push("/home", { update: true });
In home : I am trying to get params let {update} = useParams();
But update is always undefined. Whats wrong with this code. Any suggestions ?
The second parameter in the history.push() method is actually known as the location state,
history.push(path, [state])
Depending on your requirements, you may want to pass update as part of the location state, or the query string.
history.push({
pathname: '/home',
search: '?update=true', // query string
state: { // location state
update: true,
},
});
As stated on the React-Router documentation, you can access the state by accessing the location props. In your case, to get the value for update,
On class components, assuming that it is connected to the router,
this.props.location
For functional components, you can use the useLocation hook to access the location object.
import { useLocation } from 'react-router-dom';
.
.
const location = useLocation();
console.log(location.state.update) // for location state
console.log(location.search) // for query strings;
If you are using React Hooks follow this method because this.props is only available in React Class.
Component One:
import React from 'react'
import { useHistory } from "react-router-dom";
const ComponentOne = () => {
const history = useHistory();
const handleSubmit = () => {
history.push('/component-two',{params:'Hello World'})
}
return (
<div>
<button onClick={() => {handleSubmit()}}>Fire</button>
</div>
)
}
Component Two:
import React from 'react'
import { useLocation } from "react-router-dom";
const ComponentTwo = () => {
const location = useLocation();
const myparam = location.state.params;
return (
<div>
<p>{myparam}</p>
</div>
)
}
This is how you can pass
history.push("/home", { update: true });
and access like this if it's stateless component.
props.location.state.update;
if class based component.
this.props.location.update;
There's also a simpler way to access the state passed on if you're using functional components:
First, pass in the state in history.push
history = useHistory();
history.push('/path-to-component-2', 'state')
Next, u can retrieve the state in the location props
const Component2 = ({ location }) => {
console.log(location.state);
return null;
};

How to redirect to a new page from a function in React?

Right now I have this function in react and I am using it to go back to login and also to check reset the localStorage value for which I am using the function and not since using that I cannot reset local storage value. The function is below:-
logout(){
localStorage.clear();
console.log("cliasdk");
return(
<Redirect to="/login"/>
)
}
This gets executed on clicking a div but I am not able to go to the /login page.How to do it?
If you use the react-router-dom package you can wrap your component with a router and then you have the ability to redirect the user programmatically, like so this.props.history.push('/login').
Eg:
import {withRouter} from 'react-router-dom';
class Component extends React.component {
constructor(props){
}
componentDidMount(){
this.props.history.push('/login');
}
}
export default withRouter(Component);
See: https://www.npmjs.com/package/react-router-dom.
With all previous answers, I'll describe here this use case:
on `/login` page, I would like to go to `/` when login is OK:
Add imports:
import { Redirect } from 'react-router-dom';
Add in your component default state a redirect to false:
state = {
redirect: false,
}
Add to your business logic (ex. onLoginOk()) a change of the redirect state
this.setState({ redirect: true })
Add somewhere in your render root element:
{ this.state.redirect ? (<Redirect push to="/"/>) : null }
That's it.
you can use this example for redirect after rendering a function
import React from 'react';
import { Redirect } from 'react-router-dom';
class MyComponent extends React.Component {
state = {
redirect: false
}
setRedirect = () => {
this.setState({
redirect: true
})
}
renderRedirect = () => {
if (this.state.redirect) {
return <Redirect to='/target' />
}
}
render () {
return (
<div>
{this.renderRedirect()}
<button onClick={this.setRedirect}>Redirect</button>
</div>
)
}
}
You can use history variable in props or if haven't history in props, you can use withRouter HOC (https://reacttraining.com/react-router/web/api/withRouter)
history.push("/login")
or
history.replace("/login")
This is the simplest if you don't want to deal with react-router-dom.
Here's an example written in react functional components
const Page = () => {
const redirect = () => {
window.location.href = '/anotherPagePath'
}
return (
<button onClick={redirect}>go to another page</button>
)
}
import React from "react"
import { useHistory } from "react-router-dom";
export const Component = ( props ) => {
const history = useHistory()
const handler = () => {
//Redirect to another route
history.push("/route-link")
}
}
Maybe that's what you are looking for.
If you are trying to logout in a React application (that uses the URL pattern /#/page) through a function that clean the local storage / redirect, try to use go:
import { createHashHistory } from "history";
const history = createHashHistory();
history.go("/login");
The go loads a specific URL from the history list, this can be used to go back in the history, but also to go foward, in this case the 'foward' will use /login and the absolute path to redirect.
Update
On React Router 6 you can use useNavigate to navigate programmatically
In React router 6, redirection looks like this:
const navigate = useNavigate();
const goToLoginPage = () => navigate('/login');
All the code can be seen here:
https://github.com/anmk/redirect/blob/redirect/src/App.js
You can also write a component to do this:
https://github.com/anmk/redirect/tree/redirect_to_component
You can change route programmatically, with history like this:
export default class Logout extends Component {
logout = () => {
this.props.history.push("login");
};
render() {
return (
<div>
<h1>Logout</h1>
<button onClick={this.logout}>Logout</button>
</div>
);
}
}
If you need localStorage.clear();, just put it in logout function. You can see full (working) code example here: https://codesandbox.io/s/py8w777kxj
For future reference, if you're not interested in using React Router you could try the same as I use right now which uses the browser's location (URL):
logout(){
// stuff...
location.href = "/login/"
}
Try this
import React from "react";
const createHistory = require("history").createBrowserHistory;
class Logout extends React.Component {
constructor(props) {
super(props);
let history = createHistory();
history.push("/login");
let pathUrl = window.location.href;
window.location.href = pathUrl;
}
render() {
return (
<div>
</div>
);
}
}
export default Logout;
logout(){
localStorage.clear();
this.setState({redirect: true})
}
//inside Render
render(){
const {redirect} = this.state;
if(redirect){
return <Redirect push to="/login"/>
}
}
You need to import Redirect from react-router-dom, like this:
import { Redirect } from 'react-router-dom';
This is how I solved the problem.
import {useDispatch} from "react-redux";
import useRouter from 'hooks/useRouter'
const {push} = useRouter();
const dispatch = useDispatch();
const logout = () => {
localStorage.clear();
push("/login");
dispatch({
type: LOGOUT_STARTED,
payload: false,
});
};
<... onClick={logout} ..>

Resources