How to write logout function in functional component using reactjs? - 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();

Related

mapStateToProps react router dom v6 useParams()

BlogDetailsPage.js
import { connect } from "react-redux";
import { useParams } from "react-router-dom";
const BlogDetailsPage = (props) => {
const { id } = useParams();
return <div>Blog Details: {}</div>;
};
const mapStateToProps = (state, props) => {
const { id } = useParams();
return {
blog: state.blogs.find((blog) => {
return blog.id === id;
}),
};
};
export default connect(mapStateToProps)(BlogDetailsPage);
How to use mapStateToProps in "useParams()" react-router-dom ?
and whatever links that navigate to /slug path are ended up in BlogDetailsPage.js, Since BlogDetailsPage.js is being nested nowhere else so i couldn't get specific props pass down but route params. From my perspective this is completely wrong but i couldn't figure out a better way to do it.
Compiled with problems:X
ERROR
src\components\BlogDetailsPage.js
Line 11:18: React Hook "useParams" is called in function "mapStateToProps" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use" react-hooks/rules-of-hooks
Search for the keywords to learn more about each error.```
Issue
React hooks can only be called from React function components or custom React hooks. Here it is being called in a regular Javascript function that is neither a React component or custom hook.
Solutions
Preferred
The preferred method would be to use the React hooks directly in the component. Instead of using the connect Higher Order Component use the useSelector hook to select/access the state.blogs array.
Example:
import { useSelector } from 'react-redux';
import { useParams } from 'react-router-dom';
const BlogDetailsPage = () => {
const { id } = useParams();
const blog = useSelector(state => state.blogs.find(
blog => String(blog.id) === id
));
return <div>Blog Details: {}</div>;
};
export default BlogDetailsPage;
Alternative/Legacy
If you have the need to access path params in any mapStateToProps function, if you are using a lot of oder code for example, then you'll need to create another HOC to access the path params and have them injected as props so they are available in the mapStateToProps function.
Example:
import { useParams, /* other hooks */ } from "react-router-dom";
const withRouter = Component => props => {
const params = useParams();
// other hooks, useLocation, useNavigate, etc..
return <Component {...props} {...{ params, /* other injected props */ }} />;
};
export default withRouter;
...
import { compose } from 'redux';
import { connect } from 'react-redux';
import withRouter from '../path/to/withRouter';
const BlogDetailsPage = ({ blog }) => {
return <div>Blog Details: {}</div>;
};
const mapStateToProps = (state, { params }) => {
const { id } = params || {};
return {
blog: state.blogs.find((blog) => {
return String(blog.id) === id;
}),
};
};
export default compose(
withRouter, // <-- injects a params prop
connect(mapStateToProps) // <-- props.params accessible
)(BlogDetailsPage);
I think, react hook functions are allowed to use inside of react component.
Outside of react components, it's not allowed to use react api hook functions.
Thanks, I'd liked to help you my answer.

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

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";

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 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