How to get rid of this ? from the url - reactjs

I'm making a react application and whenever I search for something(eg cat) on the homepage, the url changes to search/cat and the forward, backward button work normally & help me switch between the homepage and the cat search page ...but when i search for something again (eg rat) after(homepage->cat) so the url changes to search/rat? and now when i press the back button the url changes to search/rat and i'm on the same page then if i press back button again the url becomes search/cat but the page still has the results of the rat search and if i press back again ,the homepage appears..why is this happening?I think it's because of the ? that appears at the end of the url..Please help
after searching cat
after searching for rat
after pressing the back button
after pressing the back button
after pressing the back button
This is the code of the search bar
import React, { Component } from "react";
import "./styles/searchBar.scss";
import "font-awesome/css/font-awesome.min.css";
import { withRouter } from "react-router-dom";
import SearchForm from "./SearchForm";
import { connect } from "react-redux";
import { fetchRandomPhotos } from "../redux/actions/randomPhotoAction";
class SearchBar extends Component {
state = {
searchQuery: "",
};
componentDidMount() {
this.props.fetchRandomPhotos();
}
handleChange = (event) => {
this.setState({ searchQuery: event.target.value });
};
handleSubmit = (event) => {
//event.preventDefault();
this.props.history.push(`/search/${this.state.searchQuery}`);
};
handleProfile = () => {
this.props.history.push(`/public/${this.props.photo.user.username}`);
};
render() {
const { photo } = this.props;
return !photo ? (
<div className="search-bar-container">
<div className="search-bar-area">
<div className="about-foto-fab">
<h1>Foto-Fab</h1>
<p>The internet's source of freely-usable images.</p>
<p>Powered by creator everywhere</p>
</div>
<SearchForm
onSubmit={this.handleSubmit}
onChange={this.handleChange}
/>
</div>
</div>
) : (
<div
className="search-bar-container"
style={{ backgroundImage: `url("${photo.urls.full}")` }}
>
<div className="black-layer"></div>
<div className="search-bar-area">
<div className="about-foto-fab">
<h1>Foto-Fab</h1>
<p>The internet's source of freely-usable images.</p>
<p>Powered by creator everywhere</p>
</div>
<SearchForm
onSubmit={this.handleSubmit}
onChange={this.handleChange}
/>
</div>
<div className="picture-info">
<div className="photographer">
<p onClick={this.handleProfile}>
<strong>Photo</strong> by {""}
<strong>{photo.user.name}</strong>
</p>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
photo: state.randomPhotoState.photo,
};
};
export default connect(mapStateToProps, { fetchRandomPhotos })(
withRouter(SearchBar)
);
This is the App.js
import React from "react";
import Navbar from "./components/Navbar";
import { BrowserRouter, Switch, Route, Redirect } from "react-router-dom";
import Home from "./pages/Home";
import LoginPage from "./pages/LoginPage";
import ProfilePage from "./pages/ProfilePage";
import SearchPage from "./pages/SearchPage";
import PublicUserProfilePage from "./pages/publicUserProfilePage";
import MobileNavigation from "./components/MobileNavigation";
import AboutPage from "./pages/AboutPage";
function App() {
return (
<BrowserRouter>
<Navbar />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/login" component={LoginPage} />
<Route exact path="/profile" component={ProfilePage} />
<Route exact path="/search/:searchQuery" component={SearchPage} />
<Route exact path="/about" component={AboutPage} />
<Route
exact
path="/public/:username"
component={PublicUserProfilePage}
/>
<Redirect to="/" />
</Switch>
<MobileNavigation />
</BrowserRouter>
);
}
export default App;
search form component
import React, { Component } from "react";
export class SearchForm extends Component {
render() {
const { onSubmit, onChange } = this.props;
return (
<form className="search-form" onSubmit={onSubmit}>
<input
type="text"
placeholder="Search free high-resolution photos"
onChange={onChange}
/>
<button type="submit">
<i className="fa fa-search"></i>
</button>
</form>
);
}
}
export default SearchForm;

import React, { Component } from "react";
import "./styles/searchBar.scss";
import "font-awesome/css/font-awesome.min.css";
import { withRouter } from "react-router-dom";
import SearchForm from "./SearchForm";
import { connect } from "react-redux";
import { fetchRandomPhotos } from "../redux/actions/randomPhotoAction";
class SearchBar extends Component {
state = {
searchQuery: "",
};
componentDidMount() {
this.props.fetchRandomPhotos();
}
handleChange = (event) => {
this.setState({ searchQuery: event.target.value });
};
handleSubmit = (event) => {
event.preventDefault();
if (this.state.searchQuery) {
this.props.history.push(`/search/${this.state.searchQuery}`);
}
};
handleProfile = () => {
this.props.history.push(`/public/${this.props.photo.user.username}`);
};
render() {
const { photo } = this.props;
return !photo ? (
<div className="search-bar-container">
<div className="search-bar-area">
<div className="about-foto-fab">
<h1>Foto-Fab</h1>
<p>The internet's source of freely-usable images.</p>
<p>Powered by creator everywhere</p>
</div>
<SearchForm
onSubmit={this.handleSubmit}
onChange={this.handleChange}
/>
</div>
</div>
) : (
<div
className="search-bar-container"
style={{ backgroundImage: `url("${photo.urls.full}")` }}
>
<div className="black-layer"></div>
<div className="search-bar-area">
<div className="about-foto-fab">
<h1>Foto-Fab</h1>
<p>The internet's source of freely-usable images.</p>
<p>Powered by creator everywhere</p>
</div>
<SearchForm
onSubmit={this.handleSubmit}
onChange={this.handleChange}
/>
</div>
<div className="picture-info">
<div className="photographer">
<p onClick={this.handleProfile}>
<strong>Photo</strong> by {""}
<strong>{photo.user.name}</strong>
</p>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
photo: state.randomPhotoState.photo,
};
};
export default connect(mapStateToProps, { fetchRandomPhotos })(
withRouter(SearchBar)
);

Related

How do I display Logut button once I login to the main UI?

I am trying to implement this feature in my React JS app where if I login successfully, the UI would display the Logout button in the navbar. But if I click on the Logout, I would be logged out from the main UI and redirected to the Login Page where the navbar won't have any Logout Button. Currently, when I log in to the main UI successfully, then I have to refresh the browser tab to show the logout button. It does not appear automatically once I log in successfully.
This is my header Component:
import React, { Component } from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import AuthenticationService from "../Login/AuthenticationService";
class HeaderComponent extends Component {
render() {
const isUserLoggedIn = sessionStorage.getItem("authenticatedUser");
console.log(isUserLoggedIn);
return (
<nav className="navbar navbar-expand-lg ">
<Router>
<div className="container-fluid">
<a className="navbar-brand" href="#">
<span className="header-title">TODO APP</span>
</a>
<ul className="navbar-nav d-flex flex-row ms-auto me-3">
{isUserLoggedIn && (
<Link
to="/login"
onClick={() => {
window.location.href = "/login";
}}
>
{" "}
<button
className="btn btn-success logout-button"
onClick={AuthenticationService.logout}
>
Logout
</button>
</Link>
)}
</ul>
</div>
</Router>
{" "}
</nav>
);
}
}
export default HeaderComponent;
The isUserLoggedIn is a boolean value that is retrieved from the session storage. If isUserLoggedIn is true then the Logout button would be displayed on the Navbar.
const isUserLoggedIn = sessionStorage.getItem("authenticatedUser");
The AuthenticationService.js file is:
import React, { Component } from "react";
class AuthenticationService extends Component {
registerSuccessfulLogin(username, password) {
console.log("Login Successful");
sessionStorage.setItem("authenticatedUser", username);
console.log(sessionStorage.getItem("authenticatedUser"));
}
isUserLoggedIn() {
let user = sessionStorage.getItem("authenticatedUser");
if (user === null) {
return false;
} else {
return true;
}
// return true;
}
logout() {
sessionStorage.removeItem("authenticatedUser");
}
getLoggedInUserName() {
let user = sessionStorage.getItem("authenticatedUser");
if (user === null) return "";
return user;
}
}
export default new AuthenticationService();
The App.js component is:
import "./App.css";
import DropDownMenu from "./components/DropdownMenu/DropDownMenu";
import HeaderComponent from "./components/Header/HeaderComponent";
import LoginComponent from "./components/Login/LoginComponent";
import {
BrowserRouter as Router,
Routes,
Route,
useParams,
Link,
} from "react-router-dom";
import "./styles.css";
import "./loginStyle.css";
import "./Header.css";
import ErrorComponent from "./components/search-options/ErrorComponent";
import AuthenticatedRoute from "./components/DropdownMenu/AuthenticatedRoute";
function App() {
return (
<div className="App">
<HeaderComponent />
<Router>
<Routes>
<Route path="/" element={<LoginComponent />}></Route>
{/* <Route path="/login" element={<Navigate to="/LoginComponent" />} /> */}
<Route path="/login" default element={<LoginComponent />}></Route>
<Route
path="/pst"
element={
<AuthenticatedRoute>
<DropDownMenu />
</AuthenticatedRoute>
}
></Route>
<Route path="*" element={<ErrorComponent />}></Route>
</Routes>
</Router>
</div>
);
}
export default App;
I am not sure why do I have to refresh the Tab to show the Logout button on to the NavBar.
EDIT
I have added the Login component for further reference:
import axios from "axios";
import { data } from "jquery";
import React, { Component } from "react";
import { useNavigate } from "react-router";
import App from "../../App";
import HeaderComponent from "../Header/HeaderComponent";
import GetUserIp from "../tracking/GetUserIp";
import TrackLoginActivity from "../tracking/TrackLoginActivity";
import AuthenticationService from "./AuthenticationService";
class LoginComponent extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
ipAddress: "",
hasLoginFailed: false,
isUserLoggedIn: false,
};
this.handleCredentialChange = this.handleCredentialChange.bind(this);
this.submitLogin = this.submitLogin.bind(this);
}
handleCredentialChange(event) {
console.log(event.target.name);
this.setState({ [event.target.name]: event.target.value });
}
submitLogin(event) {
event.preventDefault();
var session_url =
"login check api url";
GetUserIp.retrieveIpAddress().then((response) => {
this.setState({ ipAddress: response.data.ip });
});
console.log(this.state.ipAddress);
axios
.post(
session_url,
{},
{
auth: {
username: this.state.username,
password: this.state.password,
},
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
}
)
.then((response) => {
console.log("Authenticated");
console.log(this.props);
AuthenticationService.registerSuccessfulLogin(
this.state.username,
this.state.password
);
this.props.navigate(`/pst`);
//track user login activity into the DB Entity, smart_tool_login_logs
TrackLoginActivity.trackSuccessfulLogin(
this.state.username,
this.state.ipAddress
);
})
.catch((error) => {
console.log("Error on autheication");
this.setState({ hasLoginFailed: true });
});
}
render() {
return (
<div className="login-app">
<form action="" className="login-form" onSubmit={this.submitLogin}>
<div className="container">
<input
type="text"
placeholder="username"
name="username"
className="username-value"
maxLength={30}
autoComplete="on"
value={this.state.username}
onChange={this.handleCredentialChange}
/>
<input
type="password"
placeholder="password"
name="password"
className="password-value"
maxLength={30}
autoComplete="on"
value={this.state.password}
onChange={this.handleCredentialChange}
/>
{this.state.hasLoginFailed && (
<div className="login-fail-message">
Invalid username/password
</div>
)}
<div className="login-btn"></div>
<button className="btn btn-success login-btn" type="submit">
Login
</button>
</div>
</form>
</div>
);
}
}
function WithNavigate(props) {
let navigate = useNavigate();
return <LoginComponent {...props} navigate={navigate} />;
}
export default WithNavigate;
Your header component is a stateless component, it has neither props nor internal state, so it is only rendered once with the initial value of isUserLoggedIn.
If you want the header component to react to the login status, it needs to be notified in some way that the value has changed. The easiest way to do so is to store this information in the state of your App component, then passing it down as a prop to the HeaderComponent.
// App.js
import "./App.css";
import DropDownMenu from "./components/DropdownMenu/DropDownMenu";
import HeaderComponent from "./components/Header/HeaderComponent";
import LoginComponent from "./components/Login/LoginComponent";
import {
BrowserRouter as Router,
Routes,
Route,
useParams,
Link,
} from "react-router-dom";
import "./styles.css";
import "./loginStyle.css";
import "./Header.css";
import ErrorComponent from "./components/search-options/ErrorComponent";
import AuthenticatedRoute from "./components/DropdownMenu/AuthenticatedRoute";
import AuthenticationService from "../Login/AuthenticationService";
function App() {
const [isUserLoggedIn, setIsUserLoggedIn] = useState(AuthenticationService.isUserLoggedIn()) // use the session storage to get the initial state's value
function onLoginSuccessful() {
setIsUserLoggedIn(true); // update the state to notify React the value has changed
}
return (
<div className="App">
<HeaderComponent isUserLoggedIn={isUserLoggedIn} /> {/* pass down the state value as a prop */}
<Router>
<Routes>
<Route path="/" element={<LoginComponent onLoginSuccessful={onLoginSuccessful}/>}></Route>
{/* <Route path="/login" element={<Navigate to="/LoginComponent" />} /> */}
<Route path="/login" default element={<LoginComponent onLoginSuccessful={onLoginSuccessful} />}></Route>
<Route
path="/pst"
element={
<AuthenticatedRoute>
<DropDownMenu />
</AuthenticatedRoute>
}
></Route>
<Route path="*" element={<ErrorComponent />}></Route>
</Routes>
</Router>
</div>
);
}
export default App;
// HeaderComponent.js
import React, { Component } from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import AuthenticationService from "../Login/AuthenticationService";
class HeaderComponent extends Component {
render() {
const isUserLoggedIn = this.props.isUserLoggedIn; // retrieve the value from the props
console.log(isUserLoggedIn);
return (
<nav className="navbar navbar-expand-lg ">
<Router>
<div className="container-fluid">
<a className="navbar-brand" href="#">
<span className="header-title">TODO APP</span>
</a>
<ul className="navbar-nav d-flex flex-row ms-auto me-3">
{isUserLoggedIn && (
<Link
to="/login"
onClick={() => {
window.location.href = "/login";
}}
>
{" "}
<button
className="btn btn-success logout-button"
onClick={AuthenticationService.logout}
>
Logout
</button>
</Link>
)}
</ul>
</div>
</Router>
{" "}
</nav>
);
}
}
export default HeaderComponent;
Note that you also have to pass a callback to LoginComponent to be called once the user successfully logs in. Using state updates, React gets notified that the value of isUserLoggedIn has changed and will re-render the components that depend on this value, including HeaderComponent.
EDIT: I updated the implementation of LoginComponent with the callback I mentionned
// LoginComponent.js
import axios from "axios";
import { data } from "jquery";
import React, { Component } from "react";
import { useNavigate } from "react-router";
import App from "../../App";
import HeaderComponent from "../Header/HeaderComponent";
import GetUserIp from "../tracking/GetUserIp";
import TrackLoginActivity from "../tracking/TrackLoginActivity";
import AuthenticationService from "./AuthenticationService";
class LoginComponent extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
ipAddress: "",
hasLoginFailed: false,
isUserLoggedIn: false,
};
this.handleCredentialChange = this.handleCredentialChange.bind(this);
this.submitLogin = this.submitLogin.bind(this);
}
handleCredentialChange(event) {
console.log(event.target.name);
this.setState({ [event.target.name]: event.target.value });
}
submitLogin(event) {
event.preventDefault();
var session_url =
"login check api url";
GetUserIp.retrieveIpAddress().then((response) => {
this.setState({ ipAddress: response.data.ip });
});
console.log(this.state.ipAddress);
axios
.post(
session_url,
{},
{
auth: {
username: this.state.username,
password: this.state.password,
},
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
}
)
.then((response) => {
console.log("Authenticated");
console.log(this.props);
AuthenticationService.registerSuccessfulLogin(
this.state.username,
this.state.password
);
// add this line to your `LoginComponent` so that
// onLoginSuccessul is called when user is logged in
this.props.onLoginSuccessful();
this.props.navigate(`/pst`);
//track user login activity into the DB Entity, smart_tool_login_logs
TrackLoginActivity.trackSuccessfulLogin(
this.state.username,
this.state.ipAddress
);
})
.catch((error) => {
console.log("Error on autheication");
this.setState({ hasLoginFailed: true });
});
}
render() {
return (
<div className="login-app">
<form action="" className="login-form" onSubmit={this.submitLogin}>
<div className="container">
<input
type="text"
placeholder="username"
name="username"
className="username-value"
maxLength={30}
autoComplete="on"
value={this.state.username}
onChange={this.handleCredentialChange}
/>
<input
type="password"
placeholder="password"
name="password"
className="password-value"
maxLength={30}
autoComplete="on"
value={this.state.password}
onChange={this.handleCredentialChange}
/>
{this.state.hasLoginFailed && (
<div className="login-fail-message">
Invalid username/password
</div>
)}
<div className="login-btn"></div>
<button className="btn btn-success login-btn" type="submit">
Login
</button>
</div>
</form>
</div>
);
}
}
function WithNavigate(props) {
let navigate = useNavigate();
return <LoginComponent {...props} navigate={navigate} />;
}
export default WithNavigate;

How can I get the input of a textfield in ReactJS? I am trying to make a specific calculator and need the inputs from the User

I am using material-UIs text fields and want to get the value from the user's input. Right now I am just trying to log the value to the console, so I can see it is getting the value but, it is logging blank. How can I get the Input from the text field?
The Input cards are a component with the text field along with a few other design things.
import "./StartPage.scss";
import React, { Component } from "react";
import InputCard from '../components/InputCard';
import {BrowserRouter as Router, Switch, Route, Link} from 'react-router-dom';
import ResultsPage from '../pages/ResultsPage';
import InputToFormula from "../components/InputToFormula";
import PropTypes from 'prop-types';
import { evaluate } from "mathjs";
import * as math from "mathjs";
import { tsConstructorType } from "#babel/types";
class StartPage extends Component {
constructor(props) {
super(props);
this.state = {
setBots: "",
setEmployees: "",
setSalary: "",
setTime: ""
};
};
handleBots = event => {
this.setState({ setBots: event.target.value});
};
handleEmployees = event => {
this.setState({ setEmployees: event.target.value});
};
handleSalary = event => {
this.setState({ setSalary: event.target.value});
};
handleTime = event => {
this.setState({ setTime: event.target.value});
};
logValue = () => {
console.log(this.state.setBots);
};
render(){
return (
<div className="container">
<div className="header-container">
<h2> </h2>
<h1>Return on Investment Calculator</h1>
<h2> </h2>
</div>
<form>
<div class="inputs input-group">
<InputCard onEvent={this.handleBots} id="Bots" icon="robot" label="Number of Processes" />
<InputCard onEvent={this.handleEmployees} id="Employees" icon="users" label="Number of FTE's" />
<InputCard onEvent={this.handleSalary} id="Salary" icon="dollar-sign" label="Average Salary" />
<InputCard onEvent={this.handleTime} id="Time" icon="clock" label="Average Time (%)" />
</div>
<Router>
<div>
<h1> </h1>
<Link to='/ResultsPage'><button onClick={this.logValue} type="button"
class="btn btn-outline-success submit-button btn-lg">CALCULATE</button></Link>
</div>
<Switch>
<Route path="/ResultsPage" exact>
<ResultsPage />
</Route>
</Switch>
</Router>
</form>
</div>
);
}
}
export default StartPage;
Use onChange instead of onEvent, here you can read more about it

Getting my page to Route properly with ReactJS

Have a pretty basic app through ReactJS but having trouble with routing to a new page and can't figure out why. When I click on the box that should route me to the Quiz page, the contents on that page populate (just saying "hello") but everything else on the page stays the same. I thought it had to do with the exact path but even still, everything remains the same and doesnt just show what's within my Quiz Component. Any thoughts? Appreciate all the help!
APP.JS
import React, { Component } from 'react';
import { Route, Link, Switch } from 'react-router-dom';
import Home from "./Components/Home/Home"
import Header from "./Components/Header/Header"
import Modal from "./Components/Modal/Modal"
import Quiz from "./Components/Quiz/Quiz"
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
questions: this.props.questions,
show: false,
};
}
// Function that opens/closes Modal
showModal = () => {
this.setState({ show: !this.state.show })
}
render() {
return (
<div>
<header>
<Header />
{/* Input button for Modal */}
<input
className='open-modal-btn'
type='button'
onClick={this.showModal}
value=' Show Modal'
/>
<Modal show={this.state.show} onClose={this.showModal}>
This message is from Modal
</Modal>
</header>
<Home />
<div>
<Switch>
<Route
exact
path='/quiz'
render={() => {
return (
<Quiz />
);
}}
/>
</Switch>
</div>
</div>
);
}
}
export default App;
Home.JS
import React, { Component } from 'react';
import './Home.css';
import { Link } from 'react-router-dom';
class Home extends Component {
constructor(props) {
super(props);
this.state = { username: '' };
}
// Updates the name of the User input Box
handleChange = (event) => {
this.setState({ username: event.target.value });
};
render() {
return (
<main>
<div>
<form>
<label htmlFor='Username'> Username: </label>
<input
type='text'
name='username'
value={this.state.username}
onChange={this.handleChange}
/>
</form>
<div className='Allboxes'>
<div className='boxOne'>
<b> Name: </b> {this.state.username} <br />
<b> From: </b> Boston, MA <br />
<b> Interests: </b>Long walks on the beach, Golden Girls <br />
</div>
<div className='boxTwo'>
<b> Name: </b> {this.state.username} <br />
<b> From: </b> Dallas, TX <br />
<b> Interests: </b>Opera, Dank Memes <br />
</div>
<div className='boxThree'>
<b> Name: </b> {this.state.username} <br />
<b> From: </b> Long Beach, CA <br />
<b> Interests: </b>Shredding the Gnar, playing with yoyo's <br />
</div>
<Link to='/quiz'>
<div className='boxFour'>
<b> Name: </b> {this.state.username} <br />
<b> From: </b> Chicago, IL <br />
<b> Interests: </b>Pokemon, More Pokemon, Daisies <br />
</div>
</Link>
</div>
</div>
</main>
);
}
}
export default Home;
QUIZ.JS
import React, { Component } from 'react';
class Quiz extends Component {
render() {
return (
<div>
Hello
</div>
);
}
}
export default Quiz;
HEADER.JS
import React, { Component} from 'react';
import './Header.css';
import { Link } from 'react-router-dom';
class Header extends Component {
render() {
return (
<div>
<h1> Who Wants to be a Tandem Millionaire </h1>
<Link to='/'> Home </Link>
</div>
);
}
}
export default Header;
MODAL.JS
import React, { Component } from 'react';
import './Modal.css';
export default class Modal extends React.Component {
// Function that closes the Modal Button
onClose = (e) => {
this.props.onClose && this.props.onClose(e);
};
render() {
if (!this.props.show) {
return null;
}
return (
<div className='backdropStyle'>
<div className='modalStyle'>
{this.props.children}
<div className='footerStyle'>
<button
className='close-modal-btn'
onClick={(e) => {
this.onClose(e);
}}>
Close
</button>
</div>
</div>
</div>
);
}
}
I think the bug here could be that you did not wrap your App.js with Browser Router
Code below is a simple structuring of react-router
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom'
import React from 'react'
const App = ()=>{
<Router>
<Switch>
<Route path="/another-route" exact={true}>
<AnotherComponent />
</Route>
<Route path="/" exact={true}>
<HomeComponent />
</Route>
</Switch>
</Router>
}
So following such a structure will get your React Routing well and even cleaner having App.js structured in such format,
You can also refer to the documentation if what I wrote does not make any sense
https://reactrouter.com/web/guides/quick-start

action is not a function react-redux

login undefined
I am getting login as undefined, whenever I click the login button it was working fine before I created AppRoutes.js and moved some of the routes into that file.
TypeError: login is not a function
here is the code structure.
this is the main file where app is started and login route is put here inside the AppRoutes component.
app.js
import React, { Fragment, useEffect } from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import Navbar from './components/layout/Navbar'
import Landing from './components/layout/Landing'
import Alert from './components/layout/Alert'
import { loadUser } from './actions/auth'
import { Provider } from 'react-redux'
import setAuthToken from './utils/setAuthToken'
import store from './store'
import './App.css'
import AppRoutes from './components/routing/AppRoutes'
if (localStorage.token) {
setAuthToken(localStorage.token)
}
const App = () => {
useEffect(() => {
store.dispatch(loadUser())
}, [])
return (
<Provider store={store}>
<Router >
<Fragment>
<Navbar />
<Alert />
<Switch>
<Route exact path='/' component={Landing} />
<Route component={AppRoutes} />
</Switch>
</Fragment>
</Router>
</Provider>
)
}
export default App
2.AppRoutes.js
import React, { Fragment } from 'react'
import { Register } from '../auth/Register'
import { Login } from '../auth/Login'
import Dashboard from '../dashboard/Dashboard'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import PrivateRoute from './PrivateRoute'
import { NotFound } from '../layout/NotFound'
import store from '../../store'
import { Provider } from 'react-redux'
const AppRoutes = () => {
return (<Fragment>
<Switch>
<Route exact path='/register' component={Register} />
<Route exact path='/login' component={Login} />
<PrivateRoute path='/dashboard' component={Dashboard} >
</PrivateRoute>
<Route component={NotFound} />
</Switch>
</Fragment>
)
}
export default AppRoutes
auth.js
export const login = (email, password) => async dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
const body = JSON.stringify({ email, password })
try {
const res = await axios.post('/api/auth', body, config)
if (res?.data?.token) {
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
})
dispatch(loadUser())
}
else {
dispatch(setAlert(res.data.msg, 'success'))
}
} catch (error) {
const errors = error.response.data.errors
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')))
}
dispatch({
type: LOGIN_FAIL
})
}
}
4.Login.js
import React, { Fragment, useState } from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { login } from '../../actions/auth'
import { Link, Redirect } from 'react-router-dom'
import store from '../../store'
export const Login = ({ isAuthenticated, login }) => {
const [formData, setFormData] = useState({
email: '',
password: ''
})
const { email, password } = formData
const onChange = e => setFormData({ ...formData, [e.target.name]: e.target.value })
const onSubmit = e => {
e.preventDefault()
console.log(typeof login)
login(email, password)
}
//redirect if logged in
if (isAuthenticated) {
return <Redirect to='/dashboard' />
}
return (
<Fragment>
<div className="m-5">
<div className="row justify-content-center">
<div className="col-md-4">
<div className="card shadow-lg o-hidden border-0 my-5">
<div className="card-body p-0">
<div>
<div className="p-5">
<div className="text-center">
<h4 className="text-dark mb-4">Welcome Back!</h4>
</div>
<form className="user" onSubmit={e => onSubmit(e)}>
<div className="form-group">
<input className="form-control form-control-user" type="email" placeholder="Email Address" name="email" value={email} onChange={e => onChange(e)} required />
</div>
<div className="form-group">
<input className="form-control form-control-user" type="password"
placeholder="Password"
name="password"
minLength="6"
value={password} onChange={e => onChange(e)}
/>
</div>
<div className="form-group">
<div className="custom-control custom-checkbox small">
<div className="form-check">
<input className="form-check-input custom-control-input" type="checkbox" id="formCheck-1" />
<label className="form-check-label custom-control-label" htmlFor="formCheck-1">Remember Me</label>
</div>
</div>
</div><button className="btn btn-dark btn-block text-white btn-user" type="submit">Login</button>
<hr />
</form>
<div className="text-center"><Link to="/register" className="small" href="register.html">Create an Account!</Link></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Fragment >
)
}
Login.propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
}
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
})
export default connect(mapStateToProps, { login })(Login)
I am not able to figure out whether it is related to the route structure that i changed or is there a bigger problem that I am missing out on.
You have imported Login a named import in AppRoutes, whereas the connected component with Login was a default export which is why you see the issue
Change
import { Login } from '../auth/Login'
to
import Login from '../auth/Login'

Redirect doesn't redirect to components

This is my index.js page
import React from 'react';
import ReactDOM from 'react-dom';
import Login from './Login';
import Dashboard from './Dashboard';
import { BrowserRouter as Router, Route} from 'react-router-dom';
import './css/bootstrap.min.css';
import './css/font-awesome.min.css';
import './css/style.css';
import { createHistory, useBasename } from 'history'
const history = useBasename(createHistory)({
basename: '/'
})
ReactDOM.render((
<Router history={history}>
<div>
<Route path="/" component={Login} />
<Route path="dashboard" component={Dashboard} store={Dashboard} />
<Route exact path="login" component={Login} store={Login} />
</div>
</Router>
),
document.getElementById('root')
);
This is my login page. But clicking on the button doesn't redirect to the corresponding component.
import React, { Component } from 'react';
export default class Login extends Component {
constructor (props){
super(props);
this.state = {
email : '',
password : '',
userId : ''
};
}
login(){
//this.props.router.push('/dashboard'); // Its was not working
this.props.history.push('dashboard'); //Its working for me
}
render() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="login-page-block-inner">
<div className="login-page-block-form">
<div className="form-actions">
<button type="button" className="btn btn-primary width-150" onClick={(e) => { this.login()} }>Sign In</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
In your case this.props.router would be undefined. Here's a rough solution that I made. Reading the comments in the code will help.
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom'; // add this import
export default class Login extends Component {
constructor (props){
super(props);
this.state = {
email : '',
password : '',
userId : '',
redirectToReferrer: true // when you're checking if the user is authenticated you have to keep this false
};
}
// componentWillReceiveProps(nextProps) {
// if ( put your authentication logic here ) {
// this.setState({ redirectToReferrer: true });
// }
// }
login(){
this.props.history.push('/dashboard');
}
render() {
const from = { pathname: '/dashboard' };
const { redirectToReferrer } = this.state; // redirectToReferrer is true in the initial state
if (redirectToReferrer) { // if true the user will be redirected to /dashboard
return <Redirect to={from} />;
}
return (
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="login-page-block-inner">
<div className="login-page-block-form">
<div className="form-actions">
<button type="button" className="btn btn-primary width-150" onClick={(e) => { this.login()} }>Sign In</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
In React 16 and above you can use Redirect from 'react-router-dom'
import { Redirect } from 'react-router-dom'
Define state in your component
this.state = {
loginStatus:true
}
than in your render method
render () {
if(this.state.loginStatus){
return <Redirect to='/home' />
}
return(
<div> Please Login </div>
)
}
Make use of withRouter frun react-router to inject router as a prop to your login component
import React, { Component } from 'react';
import {withRouter} from 'react-router'
import $ from 'jquery';
class Login extends Component {
constructor (props){
super(props);
this.state = {
email : '',
password : '',
userId : ''
};
}
login(){
this.props.history.push('/dashboard');
}
render() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="login-page-block-inner">
<div className="login-page-block-form">
<div className="form-actions">
<button type="button" className="btn btn-primary width-150" onClick={(e) => { this.login()} }>Sign In</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default withRouter(Login)

Resources