0

I am creating signin/signout pages in react The header contains signin, signup or sign out links depending on whether the user is signed in or not. After Signing in, if the user clicks on sign out link he should be redirected to signout route. The url is changing to sign out route but the signout component is not being rendered. I can still see the signin component itself.

EDIT

The sign out component renders fine when I directly enter the url in the browser. It is not rendering only when the link (Link component in react-router-dom ) to signout route is clicked

Header component:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';

class Header extends Component {
  renderLinks() {
    if(this.props.authenticated) {
      return (
        <li className="nav-item">
          <Link to="/signout" className="nav-link">Sign Out</Link>
        </li>
      );
    }
    else {
      return (
        [
          <li className="nav-item" key={1}>
            <Link to="/signin" className="nav-link">Sign In</Link>
          </li>,
          <li className="nav-item" key={2}>
            <Link to="/signup" className="nav-link">Sign Up</Link>
          </li>
        ]
      );
    }
  }

  render () {
    return (
      <nav className="navbar navbar-light">
        <Link to="/" className="navbar-brand">Redux Auth</Link>
        <ul className="nav navbar-nav">
            {this.renderLinks()}
        </ul>
      </nav>
    );
  }
}

const mapStateToProps = (state) => {
  return { authenticated: state.auth.authenticated };
}

export default connect(mapStateToProps)(Header);

SignIn component:

import React, { Component } from 'react';
import { reduxForm, Field } from 'redux-form';
import { connect } from 'react-redux';

import * as actions from '../../actions';

class Signin extends Component {
  handleFormSubmit({ email, password }) {
    console.log(email, password);

    this.props.signinUser({ email, password });
  }

  renderAlert() {
    if(this.props.errorMessage) {
      return (
        <div className="alert alert-danger">
          <strong>Oops!</strong> { this.props.errorMessage }
        </div>
      );
    }
  }

  render() {
    const { handleSubmit } = this.props;

    return (
      <form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
        <div className="form-group">
          <label>Email:</label>
          <div>
            <Field
              className="form-control"
              name="email"
              component="input"
              type="text"
            />
          </div>
        </div>
        <div className="form-group">
          <label>Password:</label>
          <div>
            <Field
              className="form-control"
              name="password"
              component="input"
              type="password"
            />
          </div>
        </div>
        {this.renderAlert()}
        <div>
          <button action="submit" className="btn btn-primary">Sign In</button>
        </div>
      </form>
    );
  }
}

const mapStateToProps = (state) => {
  return { errorMessage: state.auth.error };
}

Signin =  reduxForm({
  form: 'signin',
})(Signin);

export default Signin = connect(mapStateToProps, actions)(Signin);

Signout component:

import React, { Component } from 'react';
import Header from './header';

export default class Signout extends Component {

  render() {
    return <div>Sorry to see you go...</div>;
  }
}

Main index file:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import reduxThunk from 'redux-thunk';

import App from './components/app';
import Signin from './components/auth/signin';
import Signout from './components/auth/signout';

import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <Router>
      <div>
        <Route path="/" component={App} />
        <Route path="/signin" component={Signin} />
        <Route path="/signout" component={Signout}/>
      </div>
    </Router>
  </Provider>
  , document.querySelector('.container'));

If you want to check out the entire code. It is present at this git repository

https://github.com/sruthisripathi/react-auth

EDIT

I tried using withRouter inside Header component as below

export default withRouter(connect(mapStateToProps)(Header));

I tried passing props to Header inside App component

<Header {...this.props} />

But none of this worked.

EDIT

Changing the signin and signout routes to App component instead of index file solved the issue.

App component:

import React, { Component } from "react";
import { Route } from "react-router-dom";
import Signin from "../components/auth/signin";
import Signout from "../components/auth/signout";

import Header from "./header";

export default class App extends Component {
  render() {
    return (
      <div>
        <Header />
        <Route path="/signin" component={Signin} />
        <Route path="/signout" component={Signout} />
        <Route path="/signup" component={Signout} />
      </div>
    );
  }
}

index.js file:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import reduxThunk from 'redux-thunk';

import App from './components/app';
import Signin from './components/auth/signin';
import Signout from './components/auth/signout';

import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <Router>
      <div>
        <Route path="/" component={App} />
      </div>
    </Router>
  </Provider>
  , document.querySelector('.container'));
troglodyte07
  • 3,598
  • 10
  • 42
  • 66
  • Check the duplicate, you App component renders the Header but Header doesn't receive router props, either write `
    ` or use `withRouter` on Header like `export default withRouter(connect(mapStateToProps)(Header));`
    – Shubham Khatri Feb 15 '18 at 07:32
  • @ShubhamKhatri Hi, I made edits in the question after looking at the duplicate you mentioned. Pls have a look. I can't use exact path and withRouter did not change anything. – troglodyte07 Feb 15 '18 at 08:15
  • You don't need withRouter in the App component, but in Header, I have already mentioned it in my comment above, also you don't need exact prop – Shubham Khatri Feb 15 '18 at 08:24
  • @ShubhamKhatri Sorry I'm sorry I did not see properly. But I did use withRouter in Header and I still face the same problem. I also tried passing props to Header as you said. Still the route not working properly – troglodyte07 Feb 15 '18 at 08:31
  • what exactly doesn't work now. Also did you remove the exact prop – Shubham Khatri Feb 15 '18 at 08:34
  • @ShubhamKhatri Same issue. When I click on the link in header for signout route. The route changes but signout component is not rendered. The signout component renders fine when I enter the url directly in the browser as I mentioned in the question. Yes I removed the exact prop – troglodyte07 Feb 15 '18 at 08:35
  • ` } />` should be ` } />` or simply `` – Shubham Khatri Feb 15 '18 at 08:36
  • @ShubhamKhatri Yes. changed it, still not working. I gave link to the entire repository. You can have a look at it. – troglodyte07 Feb 15 '18 at 08:42
  • 1
    Check this codesandbox https://codesandbox.io/s/k9q15oo703, moved some of the routes in App – Shubham Khatri Feb 15 '18 at 08:49
  • @ShubhamKhatri Moving the routes to App component worked. But why is it so? Why didn't it work when the routes are in index file? – troglodyte07 Feb 15 '18 at 08:53
  • @ShubhamKhatri Also I didn't have to pass props to
    . Worked without that
    – troglodyte07 Feb 15 '18 at 09:02

0 Answers0