How to render state directly after setting it? - javascript

Introduction: I am very new to ReactJS(I just started a week ago), but I am not using that as an excuse, so please go hard on me, if there is something that I am not understanding.
Abstract: I am trying to implement Protected Routes.
Background: Upon the Protected Route component mounting, componentDidMount() invokes a function called isAuthenticated() that changes the state of a field called, isAuthenticated. That same field is what I am checking for to determine whether the user sees the Protected Component or is routed back to the Login page.
Issue: Everytime I visit the Protected Route aka CreatePost, my logs show that isAuthenticated() is invoked after componentDidMount() but I am unsure why my UI is not reflecting those new changes, to show the user the authenticated route.
Question: Can anyone please assist or recommend a better strategy that I have not considered? I really appreciate it.
Note: If I declare the this.state.isAuthenticated field in my constructor to be true, I will see my Protected Route, but this is not my intended goal. Hope this is helpful in diagnosing the issue.
App.js:
import React, {Component} from 'react'
import './App.css'
import Signup from './components/Signup'
import Login from './components/Login'
import Feed from './components/Feed'
import CreatePost from './components/Createpost'
import ProtectedRoute from './components/Protectedroute'
import {
BrowserRouter as Router,
Switch,
Link,
Route,
Redirect
} from 'react-router-dom'
class App extends Component {
render() {
return(
<Router>
<div>
<Link to ='/signup'>Signup</Link>
<br />
<Link to = '/login'>Login</Link>
<br />
<Link to ='/create-post'>Create Post</Link>
<br />
<Link to ='/feed'>Feed</Link>
</div>
<Switch>
<Route path = '/signup' component = {Signup} />
<Route path = '/login' component = {Login} />
<Route path = '/feed' component = {Feed} />
<ProtectedRoute path = '/create-post' component = {CreatePost} />
</Switch>
</Router>
)
}
}
export default App
ProtectedRoute.js
import React, {Component} from 'react'
import { Redirect } from 'react-router-dom'
class ProtectedRoute extends Component {
constructor(props) {
super(props)
this.state = {
isAuthenticated: false
}
this.isAuthenticated = this.isAuthenticated.bind(this)
}
componentDidMount() {
console.log('--componentDidMount--')
this.isAuthenticated()
}
isAuthenticated() {
console.log('--isAuthenticated--')
this.setState({isAuthenticated: true})
}
render() {
const Component = this.props.component
return this.state.isAuthenticated ? (<Component />) : (<Redirect to = '/login' />)
}
}
export default ProtectedRoute

Instead of setting state inside the component for that api call try creating a function and then returning the api response as true or success
import React, { Component } from "react";
import { Redirect, Route } from "react-router-dom";
class ProtectedRoute extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false
};
this.isAuthenticated = this.isAuthenticated.bind(this);
}
componentDidMount() {
console.log("--componentDidMount--");
this.isAuthenticated();
}
isAuthenticated() {
console.log("--isAuthenticated--");
// Authentiction logic
return true;
}
render() {
const Component = this.props.component;
return (
<Route
render={props =>
this.isAuthenticated() ? (
<Component {...props} />
) : (
<Redirect to="/login" />
)
}
/>
);
}
}
export default ProtectedRoute;

Seems like the problem here that setState is async. What happens is that in the first render this.state.isAuthenticated is false and therefore immediately redirecting. You can introduce a loading state which will help you defer the rendering of the component \ redirecting to only after the state of both loading and isAuthenticated are settled.
In general never expect setState to change the state immediately in a synchronous way.

Related

React Authentication using HOC

The server sends a 401 response if the user is not authenticated and I was trying to check for authentication in the front end using a HOC as seen in Performing Authentication on Routes with react-router-v4.
However, I am getting an error saying TypeError: Cannot read property 'Component' of undefined in RequireAuth
RequireAuth.js
import {React} from 'react'
import {Redirect} from 'react-router-dom'
const RequireAuth = (Component) => {
return class Apps extends React.Component {
state = {
isAuthenticated: false,
isLoading: true
}
async componentDidMount() {
const url = '/getinfo'
const json = await fetch(url, {method: 'GET'})
if (json.status !== 401)
this.setState({isAuthenticated: true, isLoading: false})
else
console.log('not auth!')
}
render() {
const { isAuthenticated, isLoading } = this.state;
if(isLoading) {
return <div>Loading...</div>
}
if(!isAuthenticated) {
return <Redirect to="/" />
}
return <Component {...this.props} />
}
}
}
export { RequireAuth }
App.js
import React from 'react';
import { BrowserRouter as Router, Route, Switch, withRouter } from 'react-router-dom';
import SignIn from './SignIn'
import NavigationBar from './NavigationBar'
import LandingPage from './LandingPage'
import Profile from './Profile'
import Register from './Register'
import { RequireAuth } from './RequireAuth'
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<Router>
<NavigationBar />
<Switch>
<Route exact path = '/'
component = {LandingPage}
/>
<Route exact path = '/register'
component = {Register}
/>
<Route exact path = '/profile'
component = {RequireAuth(Profile)}
/>
<Route path="*" component = {() => "404 NOT FOUND"}/>
</Switch>
</Router>
</div>
);
}
}
export default withRouter(App);
I can think of some possibilities:
------- Moved this to top which eventually fixed OP's issue -------
Try remove the curly braces at {React},
import React from 'react';
------- Moved this to top which eventually fixed OP's issue -------
In RequireAuth.js, Try
const RequireAuth = ({ Component }) => {} // changed from Component to { Component }
In App.js, use Component start with capital letter
<Route exact path = '/' Component = {LandingPage}/>
Also, in <Route path="*" component = {() => "404 NOT FOUND"}/>, looks like you're not passing in a React component because the function is not returning a JSX (I can't test now so I'm not very sure, though).
try this instead:
() => <div>404 NOT FOUND</div>
or if it doesn't work, define a functional component externally and pass into the Route:
const NotFoundComponent = () => <div>404 NOT FOUND</div>
<Route path="*" component = {NotFoundComponent}/>
try to do it like this:
const RequireAuth = ({ component: Component }) => {}

Can I use ref.current.setState(...)

I have a situation that want to call a Child.method from Parent, though this is not a best practice, but I just want to give it a try. And I decide to use ref.current.setState() in the Parent component.
Here is the example code.
https://codesandbox.io/s/8lmvq3yq68
There are some unexpected behavior happened where ref, setState and react-router-dom are used together. When I use Redirect and ref together, the Child.componentDidUpdate will not be called. I wonder if it is a valid code in React? Since I can not find any doc that showing it is invalid. Or is it a bug of react-router-dom?
I logged in some additional component lifecycle logs to clarify.
So what's happening is when you select the 'Link' to '/' There are 2 parallel calls that will fire.
Navigate to the '/' route
The onClick event
So one will first navigate to the relevant route while the other will trigger the ref's function. You will see the "Calling the state change" log.
What happens when you route to the '/' path is that the SuperHero
component is unmounted! And you will see the "Unmounting - Superhero"
log. So the state change is lost and componentDidUpdate will not be fired. Nevertheless, as you can see, the redirect does happen
and the component is mounted again. Now it has no sense of the state
change but the "Mounting - Superhero" will be logged.
I have further included a separate button. Since there is no unmounting, this works as you expect!
https://codesandbox.io/s/81v0mz0548
import React from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Link,
Redirect,
Route
} from "react-router-dom";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.superheroElement = React.createRef();
}
handleClick = () => {
this.superheroElement.current.changeName();
};
render() {
return (
<Router>
<Link to={"/"} onClick={this.handleClick}>
haha
</Link>
<Route path="/" exact={true} render={() => <Redirect to="/post" />} />
<Route
path="/post"
render={props => <Superhero ref={this.superheroElement} {...props} />}
/>
<br/>
<button onClick={this.handleClick}>
haha
</button>
</Router>
);
}
}
class Superhero extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "Batman"
};
this.changeName = this.changeName.bind(this);
}
changeName() {
console.log("Calling the state change");
this.setState({
name: "Bruce Wayne"
});
}
componentDidUpdate() {
// Not called because component is unmounted
console.log("Updating - Superhero");
}
componentDidMount() {
console.log("Mounting - Superhero");
}
componentWillUnmount() {
console.log("Unmounting - Superhero");
}
render() {
return <div>{this.state.name}</div>;
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

How to properly work with Router using history to pass variables?

I'm designing a website that just like facebook or anyother website that I seen I assume works (disclosure: I'm new to web programing), what I want to do is to route to different routes but in one of my routes or possibly even more I need to pass info to the next screen route when I to the new page for example: (I'm in
www.website.com/page1 then move to www.website.com/page1/page2) whilst passing data through the state say I want to pass a date or a name but I would not want it to be shown in url. So I found that react can pass with:
<Link {to={pathname:"/page2", state:{statetopass:datatopass}}}>
However,when I do pass the state once I'm in (www.website.com/page1/page2) I'm unable to read the data only when I refresh which i find weird will I ever see the data passed, I read that history is mutable but I can't really understand what that means its probably something to do with what my problem is.
The code that I have tried so far is here:
<-------------------- APP--------------------------->
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch, IndexRoute, HashRouter } from 'react-router-dom';
import Page1 from './Page1'
import Page2 from './Page2'
import { createBrowserHistory } from "history";
const history = createBrowserHistory();//idk if history should be here seems
class App extends Component {//to make no difference
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<Router>
<Switch>
<Route exact path='/hom/Page1' component={({ match }) => { return (<Page1 />) }} />
<Route exact path='/hom/Page1/Page2' component={({ match }) => { return (<Page2 />) }} />
</Switch>
</Router>
)
}
}
export default App;
<--------------------Page1----------------->
import React, { Component } from 'react';
import { Link } from 'react-router-dom'
class Page1 extends Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
return (
<div>
<Link to={{
pathname: `Page1/Page2`,
state: { dataneed: "testme" }
}}><button>Check </button>
</Link>
</div>
)
}
}
export default Page1;
<-------------------------------Page2----------------------------->
import React, { Component } from 'react';
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
class Page2 extends Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
console.log(history.location.state.dataneed)
return (
<div>
<h1>{history.location.state.dataneed}</h1>
</div>
)
}
}
export default Page2;
So you will see that at first you get an error but then once you refresh you see the text being displayed. If anyone could suggest the best way to go about doing whta I'm trying and if anyone could help me shed some light on the matter I would greatly appreciate this.
PS: I'm using 4.3.1 version there are videos out there but those seem to use version lower than 4.0 and completely different.
I believe the issue here is the mix of React Router and the History package. React Router uses History and has a history built in to its routers, so there is no need to explicitly use createBrowserHistory or anything from History directly. Specifically the issue is that the state is passed to the Link, from React Router, but then you attempt to access the data from the createBrowserHistory() object.
What you can do to resolve this issue and keep your code a bit cleaner is basically not use createBrowserHistory directly and instead rely on the built-in history from React Router. The routing data can be accessed through props.location, props.history, and props.match, which are injected into any component wrapped in the higher-order component withRouter from React Router.
What this will look like:
In index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
ReactDOM.render((
<BrowserRouter>
<App/>
</BrowserRouter>
), document.getElementById('root'));
In App.js:
import React, { Component } from 'react';
import { Route, Switch, withRouter } from 'react-router-dom';
import Page1 from './Page1'
import Page2 from './Page2'
class App extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
{/* Note no need for a Router because we wrapped the App component in the BrowserRouter in index.js */}
<Switch>
{/* Note the component attribute can be simplified */}
<Route exact path='/hom/Page1' component={ Page1 } />
<Route exact path='/hom/Page1/Page2' component={ Page2 } />
</Switch>
)
}
}
export default withRouter(App);
Page1 is fine.
In Page2:
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
class Page2 extends Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
const { dataneed } = this.props.location.state;
return (
<div>
<h1>{ dataneed }</h1>
</div>
)
}
}
export default withRouter(Page2);
Hopefully this helps, let me know if you have questions!

React Router (Dom) v4 redirect to different route upon input enter key press

I am trying to redirect to new route when user presses enter on input field.
I have a Title and Search component that I want rendered on every page.
I have found different use cases with using Redirect component, withRouter component, using context, and possibly passing history object to my Search component which is where the input field lives. Any help would be appreciated..
App.js (main component)
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Title from './Title';
import Search from './Search';
import Home from './Home';
import Movie from './Movie';
class App extends Component {
render() {
return (
<div>
<Title />
<Search />
<Router>
<Switch>
<Route exact path='/' component={Home} />
<Route path='/movie' component={Movie} />
</Switch>
</Router>
</div>
);
}
}
export default App;
Search.js (input component)
import React, { Component } from 'react';
import './Search.css';
class Search extends Component {
constructor(props) {
super(props);
this.state = {
value: ""
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(e) {
if (e.key === 'Enter') {
// TODO redirect user to '/movie'
}
}
render() {
return (
<input type="text" id="searchTitle" placeholder="Search for a movie" onChange={this.handleChange} onKeyPress={this.handleSubmit} value={this.state.input} />
)
}
}
export default Search;
inside your handleSubmit function try:
this.props.history.push('/movie'); // or whatever
edit:
you'll probably need to bind this as well
onKeyPress={this.handleSubmit.bind(this)}
and do this to the component you're passing into the route
const HomePage = () => {
return <Home props={this.props} />
}
...
<Route ... component={HomePage} />
All other solutions I came across were outdated because of the new version.
Refer to React Router V4 / Redirect.
I have finally solved the problem by doing the following;
import { Redirect } from 'react-router-dom'
And then in my state I have declared 'submitted' as false.
postForm(e){
e.preventDefault();
this.setState({
submitted : true
})
}
When you are returning inside your render method it is going to check with your state and
render(){
if (this.state.submitted) {
return (
<Redirect to="/done"/>
)
}
return (
something else...
)
I don't know if this is one of the good solutions but unfortunately I couldn't get it to work in any other way.
You can see here to get more information in your case https://gist.github.com/verticalgrain/195468e69f2ac88f3d9573d285b09764

How to use Redirect in version 5 of react-router-dom of Reactjs

I am using the last version react-router module, named react-router-dom, that has become the default when developing web applications with React. I want to know how to make a redirection after a POST request. I have been making this code, but after the request, nothing happens. I review on the web, but all the data is about previous versions of the react router, and no with the last update.
Code:
import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Redirect } from 'react-router'
import SignUpForm from '../../register/components/SignUpForm';
import styles from './PagesStyles.css';
import axios from 'axios';
import Footer from '../../shared/components/Footer';
class SignUpPage extends React.Component {
constructor(props) {
super(props);
this.state = {
errors: {},
client: {
userclient: '',
clientname: '',
clientbusinessname: '',
password: '',
confirmPassword: ''
}
};
this.processForm = this.processForm.bind(this);
this.changeClient = this.changeClient.bind(this);
}
changeClient(event) {
const field = event.target.name;
const client = this.state.client;
client[field] = event.target.value;
this.setState({
client
});
}
async processForm(event) {
event.preventDefault();
const userclient = this.state.client.userclient;
const clientname = this.state.client.clientname;
const clientbusinessname = this.state.client.clientbusinessname;
const password = this.state.client.password;
const confirmPassword = this.state.client.confirmPassword;
const formData = { userclient, clientname, clientbusinessname, password, confirmPassword };
axios.post('/signup', formData, { headers: {'Accept': 'application/json'} })
.then((response) => {
this.setState({
errors: {}
});
<Redirect to="/"/> // Here, nothings happens
}).catch((error) => {
const errors = error.response.data.errors ? error.response.data.errors : {};
errors.summary = error.response.data.message;
this.setState({
errors
});
});
}
render() {
return (
<div className={styles.section}>
<div className={styles.container}>
<img src={require('./images/lisa_principal_bg.png')} className={styles.fullImageBackground} />
<SignUpForm
onSubmit={this.processForm}
onChange={this.changeClient}
errors={this.state.errors}
client={this.state.client}
/>
<Footer />
</div>
</div>
);
}
}
export default SignUpPage;
You have to use setState to set a property that will render the <Redirect> inside your render() method.
E.g.
class MyComponent extends React.Component {
state = {
redirect: false
}
handleSubmit () {
axios.post(/**/)
.then(() => this.setState({ redirect: true }));
}
render () {
const { redirect } = this.state;
if (redirect) {
return <Redirect to='/somewhere'/>;
}
return <RenderYourForm/>;
}
You can also see an example in the official documentation: https://reacttraining.com/react-router/web/example/auth-workflow
That said, I would suggest you to put the API call inside a service or something. Then you could just use the history object to route programatically. This is how the integration with redux works.
But I guess you have your reasons to do it this way.
Here a small example as response to the title as all mentioned examples are complicated in my opinion as well as the official one.
You should know how to transpile es2015 as well as make your server able to handle the redirect. Here is a snippet for express. More info related to this can be found here.
Make sure to put this below all other routes.
const app = express();
app.use(express.static('distApp'));
/**
* Enable routing with React.
*/
app.get('*', (req, res) => {
res.sendFile(path.resolve('distApp', 'index.html'));
});
This is the .jsx file. Notice how the longest path comes first and get's more general. For the most general routes use the exact attribute.
// Relative imports
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
// Absolute imports
import YourReactComp from './YourReactComp.jsx';
const root = document.getElementById('root');
const MainPage= () => (
<div>Main Page</div>
);
const EditPage= () => (
<div>Edit Page</div>
);
const NoMatch = () => (
<p>No Match</p>
);
const RoutedApp = () => (
<BrowserRouter >
<Switch>
<Route path="/items/:id" component={EditPage} />
<Route exact path="/items" component={MainPage} />
<Route path="/yourReactComp" component={YourReactComp} />
<Route exact path="/" render={() => (<Redirect to="/items" />)} />
<Route path="*" component={NoMatch} />
</Switch>
</BrowserRouter>
);
ReactDOM.render(<RoutedApp />, root);
React Router v5 now allows you to simply redirect using history.push() thanks to the useHistory() hook:
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>
)
}
Simply call it inside any function you like.
this.props.history.push('/main');
Try something like this.
import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Redirect } from 'react-router'
import SignUpForm from '../../register/components/SignUpForm';
import styles from './PagesStyles.css';
import axios from 'axios';
import Footer from '../../shared/components/Footer';
class SignUpPage extends React.Component {
constructor(props) {
super(props);
this.state = {
errors: {},
callbackResponse: null,
client: {
userclient: '',
clientname: '',
clientbusinessname: '',
password: '',
confirmPassword: ''
}
};
this.processForm = this.processForm.bind(this);
this.changeClient = this.changeClient.bind(this);
}
changeClient(event) {
const field = event.target.name;
const client = this.state.client;
client[field] = event.target.value;
this.setState({
client
});
}
processForm(event) {
event.preventDefault();
const userclient = this.state.client.userclient;
const clientname = this.state.client.clientname;
const clientbusinessname = this.state.client.clientbusinessname;
const password = this.state.client.password;
const confirmPassword = this.state.client.confirmPassword;
const formData = { userclient, clientname, clientbusinessname, password, confirmPassword };
axios.post('/signup', formData, { headers: {'Accept': 'application/json'} })
.then((response) => {
this.setState({
callbackResponse: {response.data},
});
}).catch((error) => {
const errors = error.response.data.errors ? error.response.data.errors : {};
errors.summary = error.response.data.message;
this.setState({
errors
});
});
}
const renderMe = ()=>{
return(
this.state.callbackResponse
? <SignUpForm
onSubmit={this.processForm}
onChange={this.changeClient}
errors={this.state.errors}
client={this.state.client}
/>
: <Redirect to="/"/>
)}
render() {
return (
<div className={styles.section}>
<div className={styles.container}>
<img src={require('./images/lisa_principal_bg.png')} className={styles.fullImageBackground} />
{renderMe()}
<Footer />
</div>
</div>
);
}
}
export default SignUpPage;
Update for react-router-dom v6, there is a useNavigate hook for condtional redirection and Link component
import { useEffect } from 'react';
import { useNavigate, Link } from 'react-router-dom';
export default function Example(): JSX.Element {
const navigate = useNavigate();
useEffect(() => {
...
if(true) { // conditional redirection
navigate('/not-found', { replace: true });
}
}, []);
return (
<>
...
<Link to="/home"> Home </Link> // relative link navigation to /home
...
</>
);
}
useNavigate
Relative Link Component
Alternatively, you can use withRouter. You can get access to the history object's properties and the closest <Route>'s match via the withRouter higher-order component. withRouter will pass updated match, location, and history props to the wrapped component whenever it renders.
import React from "react"
import PropTypes from "prop-types"
import { withRouter } from "react-router"
// A simple component that shows the pathname of the current location
class ShowTheLocation extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
}
render() {
const { match, location, history } = this.props
return <div>You are now at {location.pathname}</div>
}
}
// Create a new component that is "connected" (to borrow redux
// terminology) to the router.
const ShowTheLocationWithRouter = withRouter(ShowTheLocation)
Or just:
import { withRouter } from 'react-router-dom'
const Button = withRouter(({ history }) => (
<button
type='button'
onClick={() => { history.push('/new-location') }}
>
Click Me!
</button>
))
The problem I run into is I have an existing IIS machine. I then deploy a static React app to it. When you use router, the URL that displays is actually virtual, not real. If you hit F5 it goes to IIS, not index.js, and your return will be 404 file not found. How I resolved it was simple. I have a public folder in my react app. In that public folder I created the same folder name as the virtual routing. In this folder, I have an index.html with the following code:
<script>
{
sessionStorage.setItem("redirect", "/ansible/");
location.href = "/";
}
</script>
Now what this does is for this session, I'm adding the "routing" path I want it to go. Then inside my App.js I do this (Note ... is other code but too much to put here for a demo):
import React, { Component } from "react";
import { Route, Link } from "react-router-dom";
import { BrowserRouter as Router } from "react-router-dom";
import { Redirect } from 'react-router';
import Ansible from "./Development/Ansible";
import Code from "./Development/Code";
import Wood from "./WoodWorking";
import "./App.css";
class App extends Component {
render() {
const redirect = sessionStorage.getItem("redirect");
if(redirect) {
sessionStorage.removeItem("redirect");
}
return (
<Router>
{redirect ?<Redirect to={redirect}/> : ""}
<div className="App">
...
<Link to="/">
<li>Home</li>
</Link>
<Link to="/dev">
<li>Development</li>
</Link>
<Link to="/wood">
<li>Wood Working</li>
</Link>
...
<Route
path="/"
exact
render={(props) => (
<Home {...props} />
)}
/>
<Route
path="/dev"
render={(props) => (
<Code {...props} />
)}
/>
<Route
path="/wood"
render={(props) => (
<Wood {...props} />
)}
/>
<Route
path="/ansible/"
exact
render={(props) => (
<Ansible {...props} checked={this.state.checked} />
)}
/>
...
</Router>
);
}
}
export default App;
Actual usage: chizl.com
EDIT: changed from localStorage to sessionStorage. sessionStorage goes away when you close the tab or browser and cannot be read by other tabs in your browser.
NOTE: Answering just the title of the question
Previous Version
<Redirect from="/old-url" to="/new-url" />
Latest version
<Route path="/old-url" element={<Navigate to="/new-url" />} />
In v6 of react-router you can accomplish this using <Navigate/> tag as there is no <Redirect/> Component.
In my case. I was required to maintain the connection to the server between /Home route and /chat route; setting window.location to something would re-render that destroys client-server connection I did this.
<div className="home-container">
{redirect && <Navigate to="/chat"/>}
<div className="home__title">
....
<div className="home__group-list" onClick={handleJoin}>
</div>
const [redirect, doRedirect] = useState(false)
handleJoin changes the state of redirect to true.
you can write a hoc for this purpose and write a method call redirect, here is the code:
import React, {useState} from 'react';
import {Redirect} from "react-router-dom";
const RedirectHoc = (WrappedComponent) => () => {
const [routName, setRoutName] = useState("");
const redirect = (to) => {
setRoutName(to);
};
if (routName) {
return <Redirect to={"/" + routName}/>
}
return (
<>
<WrappedComponent redirect={redirect}/>
</>
);
};
export default RedirectHoc;
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-router-dom": "^4.2.2"
For navigate to another page (About page in my case), I installed prop-types. Then I import it in the corresponding component.And I used this.context.router.history.push('/about').And it gets navigated.
My code is,
import React, { Component } from 'react';
import '../assets/mystyle.css';
import { Redirect } from 'react-router';
import PropTypes from 'prop-types';
export default class Header extends Component {
viewAbout() {
this.context.router.history.push('/about')
}
render() {
return (
<header className="App-header">
<div className="myapp_menu">
<input type="button" value="Home" />
<input type="button" value="Services" />
<input type="button" value="Contact" />
<input type="button" value="About" onClick={() => { this.viewAbout() }} />
</div>
</header>
)
}
}
Header.contextTypes = {
router: PropTypes.object
};
Alternatively, you can use React conditional rendering.
import { Redirect } from "react-router";
import React, { Component } from 'react';
class UserSignup extends Component {
constructor(props) {
super(props);
this.state = {
redirect: false
}
}
render() {
<React.Fragment>
{ this.state.redirect && <Redirect to="/signin" /> } // you will be redirected to signin route
}
</React.Fragment>
}
Hi if you are using react-router v-6.0.0-beta or V6 in This version Redirect Changes to Navigate like this
import { Navigate } from 'react-router-dom'; // like this CORRECT in v6
import { Redirect } from 'react-router-dom'; // like this CORRECT in v5
import { Redirect } from 'react-router-dom'; // like this WRONG in v6
// This will give you error in V6 of react-router and react-router dom
please make sure use both same version in package.json
{
"react-router": "^6.0.0-beta.0", //Like this
"react-router-dom": "^6.0.0-beta.0", // like this
}
this above things only works well in react Router Version 6
The simplest solution to navigate to another component is( Example
navigates to mails component by click on icon):
<MailIcon
onClick={ () => { this.props.history.push('/mails') } }
/>
To navigate to another component you can use this.props.history.push('/main');
import React, { Component, Fragment } from 'react'
class Example extends Component {
redirect() {
this.props.history.push('/main')
}
render() {
return (
<Fragment>
{this.redirect()}
</Fragment>
);
}
}
export default Example
I found that place to put the redirect complent of react-router is in the method render, but if you want to redirect after some validation, by example, the best way to redirect is using the old reliable, window.location.href, i.e.:
evalSuccessResponse(data){
if(data.code===200){
window.location.href = urlOneSignHome;
}else{
//TODO Something
}
}
When you are programming React Native never will need to go outside of the app, and the mechanism to open another app is completely different.

Categories