147

I am working on a web application using React and bootstrap. When it comes to applying button onClick, I'm having a hard time to have page being redirect to another. If after a href, I cannot go the another page.

So would you please tell me is there any need for using react-navigation or other to navigate the page using Button onClick ?

import React, { Component } from 'react';
import { Button, Card, CardBody, CardGroup, Col, Container, Input, InputGroup, InputGroupAddon, InputGroupText, Row, NavLink  } from 'reactstrap';
 
class LoginLayout extends Component {
 
  render() {
    return (
 <div className="app flex-row align-items-center">
        <Container>
     ...
                    <Row>
                      <Col xs="6">                      
                        <Button color="primary" className="px-4">
                            Login
                         </Button>
                      </Col>
                      <Col xs="6" className="text-right">
                        <Button color="link" className="px-0">Forgot password?</Button>
                      </Col>
                    </Row>
               ...
        </Container>
      </div>
    );
  }
}
 
zadig1789
  • 55
  • 1
  • 7
Jeff Bootsholz
  • 2,971
  • 15
  • 70
  • 141

16 Answers16

194

update:

React Router v6:

import React from 'react';
import { useNavigate } from "react-router-dom";
function LoginLayout() {
  
  let navigate = useNavigate(); 
  const routeChange = () =>{ 
    let path = `newPath`; 
    navigate(path);
  }
  
  return (
     <div className="app flex-row align-items-center">
      <Container>
      ...          
          <Button color="primary" className="px-4"
            onClick={routeChange}
              >
              Login
            </Button>
      ...
       </Container>
    </div>
  );
}}

React Router v5 with hooks:

import React from 'react';
import { useHistory } from "react-router-dom";
function LoginLayout() {
  
  const history = useHistory();
  
  const routeChange = () =>{ 
    let path = `newPath`; 
    history.push(path);
  }

  return (
      <div className="app flex-row align-items-center">
        <Container>
          ...
          <Row>
            <Col xs="6">                      
              <Button color="primary" className="px-4"
                onClick={routeChange}
                  >
                  Login
                </Button>
            </Col>
            <Col xs="6" className="text-right">
              <Button color="link" className="px-0">Forgot password?</Button>
            </Col>
          </Row>
          ...
        </Container>
      </div>
  );
}
export default LoginLayout;

with React Router v5:

import { useHistory } from 'react-router-dom';
import { Button, Card, CardBody, CardGroup, Col, Container, Input, InputGroup, InputGroupAddon, InputGroupText, Row, NavLink  } from 'reactstrap';
    
class LoginLayout extends Component {
  
  routeChange=()=> {
    let path = `newPath`;
    let history = useHistory();
    history.push(path);
  }

  render() {
    return (
      <div className="app flex-row align-items-center">
        <Container>
          ...
          <Row>
            <Col xs="6">                      
              <Button color="primary" className="px-4"
                onClick={this.routeChange}
                  >
                  Login
                </Button>
            </Col>
            <Col xs="6" className="text-right">
              <Button color="link" className="px-0">Forgot password?</Button>
            </Col>
          </Row>
          ...
        </Container>
      </div>
    );
  }
}

export default LoginLayout;

with React Router v4:

import { withRouter } from 'react-router-dom';
import { Button, Card, CardBody, CardGroup, Col, Container, Input, InputGroup, InputGroupAddon, InputGroupText, Row, NavLink  } from 'reactstrap';
    
class LoginLayout extends Component {
  constuctor() {
    this.routeChange = this.routeChange.bind(this);
  }

  routeChange() {
    let path = `newPath`;
    this.props.history.push(path);
  }

  render() {
    return (
      <div className="app flex-row align-items-center">
        <Container>
          ...
          <Row>
            <Col xs="6">                      
              <Button color="primary" className="px-4"
                onClick={this.routeChange}
                  >
                  Login
                </Button>
            </Col>
            <Col xs="6" className="text-right">
              <Button color="link" className="px-0">Forgot password?</Button>
            </Col>
          </Row>
          ...
        </Container>
      </div>
    );
  }
}

export default withRouter(LoginLayout);
aravind_reddy
  • 5,236
  • 4
  • 23
  • 39
  • 2
    After using above code, I'm still on the same page. Do I need to make any extra work other than this? – Rohit Sawai Dec 09 '19 at 11:49
  • i suppose no.. did you wrap your component with `withRouter` ? – aravind_reddy Dec 09 '19 at 11:58
  • I have wrapped my component with `withRouter`. It works perfectly if I use single resource e.g. it works for the route `/MyProfile`. But that didn't work when I use `/MyProfile/edit`. How can I redirect to nested resource? – Rohit Sawai Dec 09 '19 at 12:29
  • 1
    can you add it sandbox and provide me the link so that i can better resolve your issue – aravind_reddy Dec 09 '19 at 13:11
  • 1
    Can't do that in v5.1.2 with hooks. `React Hook "useHistory" is called in function "routeChange" which is neither a React function component or a custom React Hook function.` Edit: Move `const history = useHistory()` outside of the handler if you face this issue. – carkod May 06 '20 at 23:28
  • same error Invalid hook call. Hooks can only be called inside of the body of a function component." when using React Router v5 – Johann Feb 03 '21 at 21:12
  • 1
    Not sure if this is useful, but if you're using or planning to use React router v6, you can't use `useHistory` anymore. They have replaced it with `useNavigate`. `const navigate = useNavigate(); navigate('../edit')` This will move from /some/path/profile to /some/path/edit – Pooja Kulkarni Jan 02 '22 at 07:55
77

Don't use a button as a link. Instead, use a link styled as a button.

<Link to="/signup" className="btn btn-primary">Sign up</Link>
Waleed Qidan
  • 1,072
  • 10
  • 12
40

React Router v5.1.2:

import { useHistory } from 'react-router-dom';
const App = () => {
   const history = useHistory()
   <i className="icon list arrow left"
      onClick={() => {
        history.goBack()
   }}></i>
}
May Noppadol
  • 638
  • 8
  • 9
  • 3
    I failed already on the line 'const history = useHistory()' because of 'TypeError: Cannot read property 'history' of undefined'. Did you use anything of the react-router-dom in your index.js? – ostmond Jan 24 '20 at 10:16
35

This can be done very simply, you don't need to use a different function or library for it.

onClick={event =>  window.location.href='/your-href'}
rudresh solanki
  • 925
  • 9
  • 4
20

I was trying to find a way with Redirect but failed. Redirecting onClick is simpler than we think. Just place the following basic JavaScript within your onClick function, no monkey business:

window.location.href="pagelink"
Matteus Barbosa
  • 2,409
  • 20
  • 21
12

First, import it:

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

Then, in function or class:

const history = useHistory();

Finally, you put it in the onClick function:

<Button onClick={()=> history.push("/mypage")}>Click me!</Button>
Azametzin
  • 5,223
  • 12
  • 28
  • 46
Oben Desmond
  • 161
  • 1
  • 4
8

A very simple way to do this is by the following:

onClick={this.fun.bind(this)}

and for the function:

fun() {
  this.props.history.push("/Home");
}

finlay you need to import withRouter:

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

and export it as:

export default withRouter (comp_name);
7

useHistory() from react-router-dom can fix your problem

import React from 'react';
import { useHistory } from "react-router-dom";
function NavigationDemo() {
  const history = useHistory();
  const navigateTo = () => history.push('/componentURL');//eg.history.push('/login');

  return (
   <div>
   <button onClick={navigateTo} type="button" />
   </div>
  );
}
export default NavigationDemo;
Maheshvirus
  • 6,749
  • 2
  • 38
  • 40
7

If all above methods fails use something like this:

    import React, { Component } from 'react';
    import { Redirect } from "react-router";
    
    export default class Reedirect extends Component {
        state = {
            redirect: false
        }
        redirectHandler = () => {
            this.setState({ redirect: true })
            this.renderRedirect();
        }
        renderRedirect = () => {
            if (this.state.redirect) {
                return <Redirect to='/' />
            }
        }
        render() {
            return (
                <>
                    <button onClick={this.redirectHandler}>click me</button>
                    {this.renderRedirect()}
                </>
            )
        }
    }
Paul Rumkin
  • 6,737
  • 2
  • 25
  • 35
7

if you want to redirect to a route on a Click event.

Just do this

In Functional Component

props.history.push('/link')

In Class Component

this.props.history.push('/link')

Example:

<button onClick={()=>{props.history.push('/link')}} >Press</button>

Tested on:

react-router-dom: 5.2.0,

react: 16.12.0

Aditya Patnaik
  • 1,490
  • 17
  • 27
5

If you already created a class to define the properties of your Button (If you have a button class created already), and you want to call it in another class and link it to another page through a button you created in this new class, just import your "Button" (or the name of your button class) and use the code below:

import React , {useState} from 'react';
import {Button} from '../Button';

function Iworkforbutton() {
const [button] = useState(true);

return (
    <div className='button-class'>
        {button && <Button onClick={()=> window.location.href='/yourPath'}
            I am Button </Button>
    </div>
    )
}

export default Iworkforbutton
Karl-Johan Sjögren
  • 16,544
  • 7
  • 59
  • 68
Princess
  • 51
  • 1
  • 3
2

Make sure to import {Link} from "react-router-dom"; And just hyperlink instead of using a function.

import {Link} from "react-router-dom";

<Button>
   <Link to="/yourRoute">Route Name</Link>
</Button>
1

A simple click handler on the button, and setting window.location.hash will do the trick, assuming that your destination is also within the app.

You can listen to the hashchange event on window, parse the URL you get, call this.setState(), and you have your own simple router, no library needed.

class LoginLayout extends Component {
    constuctor() {
      this.handlePageChange = this.handlePageChange.bind(this);
      this.handleRouteChange = this.handleRouteChange.bind(this);
      this.state = { page_number: 0 }
    }

  handlePageChange() {
    window.location.hash = "#/my/target/url";
  }

  handleRouteChange(event) {
    const destination = event.newURL;
    // check the URL string, or whatever other condition, to determine
    // how to set internal state.
    if (some_condition) {
      this.setState({ page_number: 1 });
    }
  }

  componentDidMount() {
    window.addEventListener('hashchange', this.handleRouteChange, false);
  }

  render() {
    // @TODO: check this.state.page_number and render the correct page.
    return (
      <div className="app flex-row align-items-center">
        <Container>
          ...
                <Row>
                  <Col xs="6">                      
                    <Button 
                       color="primary"
                       className="px-4"
                       onClick={this.handlePageChange}
                    >
                        Login
                     </Button>
                  </Col>
                  <Col xs="6" className="text-right">
                    <Button color="link" className="px-0">Forgot password </Button>
                  </Col>
                </Row>
           ...
        </Container>
      </div>
    );
  }
}
ouni
  • 3,233
  • 3
  • 15
  • 21
  • 2
    using window.location is not preferable for anyone looking to maintain any form of SPA (single page application). You have changed the browser's url and wiped out any state, etc. – Acts7Seven Feb 20 '19 at 20:42
  • When you say "wiped out any state", what do you have in mind, specifically? I am using `location.hash`, which won't cause a page reload. – ouni Feb 20 '19 at 20:47
1

With React Router v5.1:

import {useHistory} from 'react-router-dom';
import React, {Component} from 'react';
import {Button} from 'reactstrap';
.....
.....
export class yourComponent extends Component {
    .....
    componentDidMount() { 
        let history = useHistory;
        .......
    }

    render() {
        return(
        .....
        .....
            <Button className="fooBarClass" onClick={() => history.back()}>Back</Button>

        )
    }
}

Harsha N Hegde
  • 315
  • 2
  • 14
1

I was also having the trouble to route to a different view using navlink.

My implementation was as follows and works perfectly;

<NavLink tag='li'>
  <div
    onClick={() =>
      this.props.history.push('/admin/my- settings')
    }
  >
    <DropdownItem className='nav-item'>
      Settings
    </DropdownItem>
  </div>
</NavLink>

Wrap it with a div, assign the onClick handler to the div. Use the history object to push a new view.

David Buck
  • 3,752
  • 35
  • 31
  • 35
0

This also seems to work well:

<Button color="primary" tag={Link} to={"/some-page"}>
Mark
  • 36
  • 3