7

How can I move to a new page after some validation is done with React Router V4? I have something like this:

export class WelcomeForm extends Component {

    handleSubmit = (e) => {
        e.preventDefault()

        if(this.validateForm())
            // send to '/life'

    }
    render() {
        return (
            <form className="WelcomeForm" onSubmit={this.handleSubmit}>
                <input className="minutes" type="number" value={this.state.minutes} onChange={ (e) => this.handleChanges(e, "minutes")}/>
            </form>
        )
    }
}

I would like to send the user to another route. I had a look at Redirect but it seems like it would delete the current page from the history which I don't want.

Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
ocram
  • 1,384
  • 6
  • 20
  • 36

4 Answers4

12

You are using react-router v4, so you need to use withRouter with your component to access the history object’s properties, then use history.push to change the route dynamically.

withRouter:

You can get access to the history object’s properties and the closest 's match via the withRouter higher-order component. withRouter will re-render its component every time the route changes with the same props as render props: { match, location, history }.

Like this:

import {withRouter} from 'react-router-dom';

class WelcomeForm extends Component {

    handleSubmit = (e) => {
        e.preventDefault()
        if(this.validateForm())
            this.props.history.push("/life");
    }

    render() {
        return (
            <form className="WelcomeForm" onSubmit={this.handleSubmit}>
                <input className="minutes" type="number" value={this.state.minutes} onChange={ (e) => this.handleChanges(e, "minutes")}/>
            </form>
        )
    }
}

export default withRouter(WelcomeForm);
Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
  • 1
    Thanks, I tried and it gives me this error: 'TypeError: Cannot read property 'push' of undefined'. Any simpler ways? – ocram May 23 '17 at 14:46
  • use this: `this.props.history.push("/life");` check the updated answer. – Mayank Shukla May 23 '17 at 14:51
  • yes it seems to work. I would like to understand why redirect explained in other answers does not seem to work and which of the two is the better practice – ocram May 23 '17 at 14:55
  • both the ways are correct, but redirect will work when you render it, means it is a ui component so inside render method use some condition and return Redirect from there it will work, but in that answer he was simply putting that inside a method it that case it will not work i think. – Mayank Shukla May 23 '17 at 14:58
  • Hi, I tried your approach, however `this.props` does not contain history for me :( https://stackoverflow.com/questions/45199064/how-to-programmatically-navigate-to-new-path-using-hashrouter?noredirect=1#comment77365323_45199064 – Leon Gaban Jul 19 '17 at 19:21
  • @LeonGaban are you rendering the component in `withRouter` HOC like this: `export default withRouter(WelcomeForm);` check the full code as i suggested. – Mayank Shukla Jul 19 '17 at 19:24
  • 1
    Ah thanks! Yes I was missing `export default withRouter(LoginContainer)` in the export statement – Leon Gaban Jul 19 '17 at 20:22
3

You can use withRouter higher-order component which will inject history object as property. Then you can use history.push to make redirection:

import { withRouter } from 'react-router-dom';
...

class WelcomeForm extends Component {

    handleSubmit = (e) => {
        e.preventDefault()
        if(this.validateForm())
            this.props.history.push('/life');
    }

    render() {
        return (
            <form className="WelcomeForm" onSubmit={this.handleSubmit}>
                <input className="minutes" type="number" value={this.state.minutes} onChange={ (e) => this.handleChanges(e, "minutes")}/>
            </form>
        )
    }
}
export default withRouter(WelcomeForm);

To make redirection you can also use <Redirect to="/someURL" /> in some cases but this component have to be rendered so you have to use it somewhere in JSX.

Bartek Fryzowicz
  • 6,464
  • 18
  • 27
1

Depending on how you want your redirect to behave there are several options: React router docs

Redirect component

Rendering a will navigate to a new location. The new location will override the current location in the history stack, like server-side redirects (HTTP 3xx) do.

to: string - The URL to redirect to.
to: object - A location to redirect to.
push: bool - When true, redirecting will push a new entry onto the history instead of replacing the current one.

Example: <Redirect push to="/somewhere"/>

import { Route, Redirect } from 'react-router'


export class WelcomeForm extends Component {

    handleSubmit = (e) => {
        e.preventDefault()

        if(this.validateForm())
            <Redirect push to="/life"/>

    }
    render() {
        return (
            <form className="WelcomeForm" onSubmit={this.handleSubmit}>
                <input className="minutes" type="number" value={this.state.minutes} onChange={ (e) => this.handleChanges(e, "minutes")}/>
            </form>
        )
    }
}

Using withRouter HoC

This higher order component will inject the same props as Route. However, it carries along the limitation that you can have only 1 HoC per file.

import { withRouter } from 'react-router-dom'

export class WelcomeForm extends Component {

        handleSubmit = (e) => {
        e.preventDefault()
        if(this.validateForm())
            this.props.history.push("/life");

        }
        render() {
            return (
                <form className="WelcomeForm" onSubmit={this.handleSubmit}>
                    <input className="minutes" type="number" value={this.state.minutes} onChange={ (e) => this.handleChanges(e, "minutes")}/>
                </form>
            )
        }
    }
Hevar
  • 1,474
  • 1
  • 13
  • 24
  • Hey thanks. As I wrote in my question, I fear Redirect delete the current page from the browser history – ocram May 23 '17 at 14:45
  • Are you sure it will work? According to docs only rendering a `` will navigate to a new location. and you don't render it. – Bartek Fryzowicz May 23 '17 at 14:46
  • if you add `push`it will keep the history. – Hevar May 23 '17 at 14:46
  • add push where? – ocram May 23 '17 at 14:47
  • i'm afraid it doesnt work: it says: 'Expected an assignment or function call and instead saw an expression no-unused-expressions' – ocram May 23 '17 at 14:51
  • Hi would you mind a look? I tried all the answers in this question, but none worked: https://stackoverflow.com/questions/45199064/how-to-programmatically-navigate-to-new-path-using-hashrouter?noredirect=1#comment77365323_45199064 – Leon Gaban Jul 19 '17 at 19:15
0

If you are using TypeScript extends your component using React.Component<RouteComponentProps> to get this.props.history.push properly

class YourComponent extends React.Component<RouteComponentProps> {
    constructor(props: Readonly<RouteComponentProps>) {
        super(props)
    }

    public render(){
        // you can access history programmatically anywhere on this class
        // this.props.history.push("/")
        return (<div/>)
    }
}
return default withRouter(YourComponent)
ktutnik
  • 6,882
  • 1
  • 29
  • 34