Search code examples
reactjsformsauthenticationreact-routerhistory.js

React history.push not working from the Home component


I'm implementing authentication to my React project and I'm trying to have the Login form in my Home component. This is how my Home component looks with the Login component attached to it.

import Login from './Login'
import * as React from 'react';
import Box from "@material-ui/core/Box";

const Home = () => {
  return (
    <div>
      <Box sx={{
        width: 600,
        height: 150,
        backgroundColor: 'lightgrey',
        borderRadius: 16
      }}>
        {<h1>Welcome to our Podcast App</h1>}
        {<h2>Feel free to share your favorites or have fun listening to the ones available.</h2>}
      </Box><br/>
        < Login />
    </div>
  );
};

export default Home;

The problem is, I want to redirect my users to the podcasts page and, history.push is not working. This is how the Login component looks.

import React from "react";
import { connect } from "react-redux";
import { loginUser } from "../actions/index";
import Button from "@material-ui/core/Button";
import { Box } from "@material-ui/core";

class Login extends React.Component {
  state = {
    email: "",
    password: "",
    error: false
  };

  handleChange = (event) => {
    this.setState({
      [event.target.name]: event.target.value
    });
  };

  handleSubmit = (event) => {
    event.preventDefault();
    const { email, password } = this.state;
    this.props
      .dispatchLoginUser({ email, password }) 
      .then(() => this.props.history.push('/podcasts')) 
      .catch(() => this.setState({ error: true }));   
  };
  

  render() {
    return (
      <Box sx={{ p: 2, border: '1px solid grey' }}>
        <form onSubmit={this.handleSubmit} >
          <h3>Log In</h3>
          <p>{this.state.error && "Invalid email or password"}</p>
          <fieldset>
            <label htmlFor='email'>
              Email:
            </label>
            <input
              type='text'
              name='email'
              id='email'
              onChange={this.handleChange}
              value={this.state.email}
            />
          </fieldset>
          <fieldset>
            <label htmlFor='password'>
              Password:
            </label>
            <input
              type='password'
              name='password'
              id='password'
              onChange={this.handleChange}
              value={this.state.password}
            />
          </fieldset><br/>
          <Button variant="contained" size="small" color="inherit" type='submit'>Log In</Button>
        </form>
      </Box>
    );
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    dispatchLoginUser: (credentials) => dispatch(loginUser(credentials))
  };
};

export default connect(null, mapDispatchToProps)(Login);

If I try to log in from the Login page, it will work. But it doesn't work from the Home page. I also tried adding history to my project like another post suggested but it still doesn't work. Here's the code:

//history.js
import { createBrowserHistory } from 'history';

export default createBrowserHistory();
//index.js
import { createBrowserHistory } from 'history';

const history = createBrowserHistory();

ReactDOM.render(
  <Provider store={ store }>
    <Router history={history} >
      <App />
    </Router>
  </Provider> 
//The routes in App.js
<Route exact path='/' component={Home}/>
<Route exact path='/signup' component={Signup} />
<Route exact path='/login' component={Login} />  

Is it possible to make history.push work from the Home component? Any suggestion will be welcomed. Thank you all.


Solution

  • Is it possible to make history.push work from the Home component?

    Yes, absolutely it is. You just need to destructure it from the props object in the Home component. For this the Home component needs to actually have a defined/declared props object.

    const Home = (props) => {
      // access props.history
      return (
        ...
        <Login history={props.history} />
        ...
      );
    };
    

    or

    const Home = ({ history }) => {
      // access history
      return (
        ...
        <Login history={history} />
        ...
      );
    };
    

    Home is a function component, so it can also use the useHistory hook and pass it along.

    const Home = () => {
      const history = useHistory();
    
      return (
        ...
        <Login history={history} />
        ...
      );
    };