Navigating using react router - javascript

I want to redirect to my home route upon submitting my axios request to the api and gathering a valid response. As can be seen, Im trying to use context but in this case i get an error "context is undefined". How can i navigate to my home route in this case? I tried using history.push but that does not seem to work either. Any ideas would be much appreciated?
import React, {Component} from 'react'
import axios from 'axios'
import Home from './Home'
import {
BrowserRouter,
Link,
Route
} from 'react-router-dom'
class SignUp extends Component {
constructor(props){
super(props);
this.state = {
email: '',
password: ''
};
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
})
}
handleClick = () => {
axios
.post('http://localhost:9000/signup',{
email: this.state.email,
password: this.state.password
}).then(function(response){
console.log(response.data.success)
this.context.router.push('/home');
})
}
render(){
return(
<BrowserRouter>
<Route path="/" render={() => (
<div>
<h1> Sign Up</h1>
<input name="email" placeholder="enter your email" onChange={e => this.handleChange(e)}/>
<br/>
<input name="password" placeholder="enter your password" onChange={e => this.handleChange(e)}/>
<br/>
<button onClick={() => this.handleClick()}>submit</button>
<Route exact path="/home" component={Home}/>
</div>
)}/>
</BrowserRouter>
)
}
}
SignUp.contextTypes = {
router: React.PropTypes.func.isRequired
};
export default SignUp

Routes should be always level above of all your components (or containers). Then, when a component is "inside" router (in your case BrowserRouter) it will gain access to its context.
Also you have inside render function of another wich does not make sense at all.
So something like this should work:
import React, {Component} from 'react'
import axios from 'axios'
import Home from './Home'
import {
BrowserRouter,
Link,
Route
} from 'react-router-dom'
class SignUp extends Component {
constructor(props){
super(props);
this.state = {
email: '',
password: ''
};
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
})
}
handleClick = () => {
axios
.post('http://localhost:9000/signup',{
email: this.state.email,
password: this.state.password
}).then(function(response){
console.log(response.data.success)
this.context.router.push('/home');
})
}
render(){
return(
<div>
<h1> Sign Up</h1>
<input name="email" placeholder="enter your email" onChange={e => this.handleChange(e)}/>
<br/>
<input name="password" placeholder="enter your password" onChange={e => this.handleChange(e)}/>
<br/>
<button onClick={() => this.handleClick()}>submit</button>
</div>
)
}
}
SignUp.contextTypes = {
router: React.PropTypes.func.isRequired
};
class App extends Component {
render() {
return(
<BrowserRouter>
<Route path="/" component={SignUp} />
<Route exact path="/home" component={Home}/>
</BrowserRouter>)
}
}
export default App;
And of course move SignUp component to standalone file to keep the project clean and well structured.

Related

instance.render is not a function. (functional component)

This is my first post.
I've been reading a lot about functional components and trying everything that I could, but nothing seems to work in my case. I am getting instance.render is not a function.
Hopefully some of you can see where my error is, as I am quite new to programming. This is my code:
App.js
import React, { useEffect, useState } from 'react';
import './App.css';
import Login from "./components/Login"
import Feed from "./components/Feed"
import { BrowserRouter as Router, Route, Switch } from "react-router-dom"
const App = () => {
const [isLoggedIn, setLoggedIn] = useState(false)
const handleLogin = token => {
if (!token) return
localStorage.setItem('token', token)
setLoggedIn(true)
}
const handleLogout = () => () => {
setLoggedIn(false)
localStorage.clear()
}
return (
<div className="App">
<Router>
<Feed isLoggedIn={isLoggedIn} logout={handleLogout} />
<Switch>
<Route
exact
path='/login'
component={(props) => (
<Login {...props} onLogin={handleLogin} />
)}>
</Route>
</Switch>
</Router>
</div>
)
}
export default App;
Login.js
import React from "react"
import axios from "axios"
import { Button, Form, FormGroup, Input } from 'reactstrap'
import "../css/Login.css"
import { Link, BrowserRouter as Router, Switch, Route } from "react-router-dom"
import Signin from "./Signin"
class Login extends React.Component {
constructor (props) {
super(props)
this.state = {
user_name: "",
password: "",
error: false,
loggedIn: false,
}
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value,
})
}
login = (event) => {
event.preventDefault()
const { user_name, password } = this.state
axios("http://localhost:7001/api/login", {
method: "POST",
data: {
user_name,
password
}
})
.then((response) => {
this.props.onLogin(response.data.token)
this.setState({ loggedIn: true })
this.feedRedirect()
console.log(response.data)
})
.catch((error) => {
console.log(error)
})
this.setState({
user_name: "",
password: "",
error: false,
})
}
feedRedirect = () => {
this.props.history.push('/feed')
}
render() {
const { user_name, password, error, loggedIn } = this.state
return (
<div className="login">
<Form className="login-container" onSubmit={this.login}>
<FormGroup>
<Input
value={this.state.user_name}
onChange={this.handleChange}
name="user_name"
type="text"
className="form-control mb-2"
placeholder="Username"
/>
</FormGroup>
<FormGroup>
<Input
value={this.state.password}
onChange={this.handleChange}
name="password"
type="password"
className="form-control mb-2"
placeholder="Password"
/>
</FormGroup>
<Button className="button-login" disabled={!user_name || !password}>
Log in
</Button>
<hr />
<Router>
<Link to="/signin"> Don't have an account? Sign up here</Link>
<Switch>
<Route path="/signin" component={Signin}>
</Route>
</Switch>
</Router>
</Form>
</div>
)
}
}
export default Login;
Any help will be appreciated. Thank you in advance.

How can I pass in props from App.js to my login component?

I'm new to React. I'm having trouble with getting React to recognize a prop passed in from App.js to the Login component. Specifically what I'm trying to do is getting React to do two things: 1. To check if a user is logged in. 2. What user is currently logged in. I'm using Passport, passport-local, Mongoose, MongoDB, Axios, Express, and react-router-dom to make this happen. When I attempt to log in a user I created in the database I get the following in the console:
TypeError: "this.props.updateUser is not a function"
onSubmit login.component.js:42
App.js:
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import axios from "axios";
/* Begin Import Components */
import NavigationBar from "./components/navbar.component";
import MainLanding from "./components/main-landing.component";
import Contact from "./components/general-components/contact.component";
import Register from "./components/general-components/register.component";
import Login from "./components/general-components/login.component";
import ProductsList from "./components/product-components/products-list.component";
import ProductDetails from "./components/product-components/product-details.component";
import ProductCreate from "./components/product-components/product-create.component";
import ProductEdit from "./components/product-components/product-edit.component";
import ProductDelete from "./components/product-components/product-delete.component";
import UsersList from "./components/user-components/users-list.component";
import UserDetails from "./components/user-components/user-details.component";
import OrdersList from "./components/order-components/orders-list.component";
import OrderDetails from "./components/order-components/order-details.component";
import OrderCreate from "./components/order-components/order-create.component";
import OrderEdit from "./components/order-components/order-edit.component";
/* End Import Components */
class App extends Component {
constructor(props) {
super(props);
this.state = {
loggedIn: false,
user: {}
}
this.getUser = this.getUser.bind(this);
this.componentDidMount = this.componentDidMount.bind(this);
this.updateUser = this.updateUser.bind(this)
}
getUser() {
axios.get('http://localhost:4000/logged_in').then(response => {
console.log('Get user response: ')
console.log(response.data)
if (response.data.user) {
this.setState({
loggedIn: true,
user: response.data.user
})
} else {
console.log('Get user: no user');
this.setState({
loggedIn: false,
user: {}
})
}
})
}
componentDidMount() {
this.getUser();
}
updateUser(userObject) {
this.setState(userObject)
}
render() {
return (
<Router>
<NavigationBar />
<div className="container">
{/* Begin Routes. Begin General Routes */}
<Route path="/" exact component={MainLanding} />
<Route path="/contact" exact component={Contact} />
<Route path="/register" exact component={Register} />
<Route path='/login' render={(props) => <Login {...props} />}/>
{/* End General Routes. Begin Products Routes */}
<Switch>
<Route path="/products/" exact component={ProductsList} />
<Route path="/products/new" exact component={ProductCreate} />
<Route path="/products/:id" exact component={ProductDetails} />
<Route path="/products/:id/edit" exact component={ProductEdit} />
<Route path="/products/:id/delete" exact component={ProductDelete} />
</Switch>
{/* End Products Routes. Begin Users Routes */}
<Switch>
<Route path="/users/" exact component={UsersList} />
<Route path="/users/:id" exact component={UserDetails} />
</Switch>
{/* End Users Routes. Begin Orders Routes */}
<Switch>
<Route path="/orders/" exact component={OrdersList} />
<Route path="/orders/new" exact component={OrderCreate} />
<Route path="/orders/:id" exact component={OrderDetails} />
<Route path="/orders/:id/edit" exact component={OrderEdit} />
</Switch>
{/* End Orders Routes. End Routes */}
</div>
</Router>
);
}
}
export default App;
Login Component:
import React, { Component } from "react";
import { Col, Form, Button } from "react-bootstrap";
import axios from "axios";
class Login extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: ""
}
this.onChangeUsername = this.onChangeUsername.bind(this);
this.onchangePassword = this.onchangePassword.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChangeUsername(e) {
this.setState({
username: e.target.value
});
}
onchangePassword(e) {
this.setState({
password: e.target.value
});
}
onSubmit(e) {
e.preventDefault();
axios.post("http://localhost:4000/login", {
username: this.state.username,
password: this.state.password
}).then(res => {
console.log(res)
if (res.status === 200) {
this.props.updateUser({
loggedIn: true,
username: res.data.username
})
}
}).catch(error => {
console.log(error);
});
this.setState({
username: "",
password: ""
})
this.props.history.push("/");
}
render() {
return (
<div className="text-center">
<h2>Login</h2>
<Form onSubmit={this.onSubmit}>
<Form.Row>
<Form.Group as={Col} sm={{ span: 6 }}>
<Form.Label htmlFor="formUsername">Username</Form.Label>
<Form.Control
controlid="formUsername"
type="text"
value={this.state.username}
onChange={this.onChangeUsername}
placeholder="Enter username"
/>
</Form.Group>
<Form.Group as={Col} sm={{ span: 6 }}>
<Form.Label htmlFor="formPassword">Password</Form.Label>
<Form.Control
controlid="formPassword"
type="password"
value={this.state.password}
onChange={this.onchangePassword}
placeholder="Enter password"
/>
</Form.Group>
</Form.Row>
<Button variant="success" type="submit">
Login
</Button>
</Form>
</div>
)
}
}
export default Login;
Let me know if I need to provide any additional information. Thank you.
The function updateUser() is defined correctly but you need to pass it to the Login component:
App.js
<Route path='/login' render={(props) =>
<Login {...props} updateUser={this.updateUser} />
}/>
This will append props.updateUser to the Login component on top of all the props from the parent component (App.js).
It does seem to be that you still not put updateUser as props of Login component. You could try like this
<Route path='/login' render={(props) =>
<Login {...props} updateUser={this.updateUser} />
}/>
But, i think that this.props.updateUser() may also be come from redux of application (mapDispatchtoProps). If so, you just connect Login component to redux, don't need to put this function as props in Login component.

this.props.history don't redirect

I don't know where I'm going wrong
by clicking the enter button I validate my user and use this.props.history.push ("/ home");
and it doesn't work
my login . js
class LoginForm extends Component {
constructor(props){
super(props);
this.state = {
login:'',
password:'',
};
this.onSubmit = this.onSubmit.bind(this);
this.onChange = this.onChange.bind(this);
}
async onSubmit(e){
e.preventDefault();
const {login, password } = this.state;
const response = await api.post('/login', { login,password });
const user = response.data.user.login;
const {jwt} = response.data;
localStorage.setItem('token', jwt);
localStorage.setItem('user', user);
this.props.history.push("/home");
}
onChange(e){
this.setState({[e.target.name]: e.target.value});
}
render() {
const { errors, login, password, isLoading } = this.state;
return (
<form onSubmit={this.onSubmit}>
<label htmlFor="login">Login</label>
<input type="text" name="login" id="login" value={login} onChange={(e) => this.onChange(e)} placeholder="Informe seu login" />
<label htmlFor="password">Senha</label>
<input type="password" name="password" id="password" value={password} onChange={(e) => this.onChange(e)} placeholder="Informe sua senha"/>
<button className="btnEnt" type="submit">Entrar</button>
</form>
)
}
}
export default LoginForm;
my router . js:
import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Login from './pages/login/index';
import DashBoard from './pages/dashboard/index';
import PrivateRoute from './auth';
export default function Routes(){
console.log('a')
return(
<BrowserRouter>
<Switch>
<PrivateRoute path="/home" component = {DashBoard}/>
</Switch>
</BrowserRouter>
);
} <PrivateRoute path="/home" component = {DashBoard}/>
</Switch>
</BrowserRouter>
);
}
my auth . js :
import { Route, Redirect} from 'react-router-dom';
const isAuth = () => {
console.log('a');
if(localStorage.getItem('token') !== null) {
return true;
}
return false;
};
const PrivateRoute = ({component: Component, ...rest}) => {
return (
<Route
{...rest}
render={props =>
isAuth() ? (
<Component {...props} />
): (
<Redirect
to={{
pathname: '/',
state: {message: 'Usuário não autorizado'}
}}
/>
)}
/>
);
}
export default PrivateRoute;
my dashboard / index
import React, { Component } from 'react';
import Home from '../../components/Home';
class DashBoard extends Component {
render() {
return (
<Home />
)
}
}
export default DashBoard;
error:
Unhandled Rejection (TypeError): Cannot read property 'push' of
undefined
Uncaught (in promise) TypeError: Cannot read property 'push' of
undefined I really do not know what I can is wrong is not redirecting,
I have tried all possible alternatives.
Before you can use history in your React component, you need to wrap it in withRouter.
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/withRouter.md
import history from 'add your path'
export default function Routes() {
console.log('a')
return (
<BrowserRouter history={history}>
<Switch>
<PrivateRoute exact path="/home" component={DashBoard} />
</Switch>
</BrowserRouter>
)
}
do changes in router file
import { withRouter } from 'react-router-dom';
export default withRouter(LoginForm);
add withRouter in this component

Page is not rendering in reactjs

I am trying to get the pages by using URL but components are not rendered in the browser even I am not getting the error. So it's very hard to resolve the error.
Please Help me to get the issue.
import React, { Component } from 'react';
import { BrowserRouter as Router} from 'react-router-dom';
import Route from 'react-router-dom/Route';
class ToDoApp extends Component {
render() {
return (
<Router>
<div className="ToDoApp">
<Route path="/" exact strict Component={Index} />
<Route path="/welcome" exact strict Component={WelcomePage} />
<Route path="/login" exact strict Component={Login} />
</div>
</Router>
);
}
}
class Index extends Component {
render() {
return (<div><h1>Welcome</h1></div>);
}
}
class WelcomePage extends Component {
render() {
return (
<div>
Welcome Page
</div>
);
}
}
class Login extends Component {
constructor(props) {
super(props);
this.state = {
username: 'Ganesh',
password: '',
hasLoginFailed: false,
showSucessMessage: false
}
this.handleChange = this.handleChange.bind(this);
this.loginCheck = this.loginCheck.bind(this);
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value // for declaring variable we use []
})
}
loginCheck() {
if (this.state.username === "Ganesh" && this.state.password === 'admin') {
console.log('successful');
this.setState({ showSucessMessage: true, hasLoginFailed: false })
} else {
console.log('failed');
this.setState({ hasLoginFailed: true, showSucessMessage: false })
}
}
render() {
return (
<div>
{/* True && 'String Value' -> String Value
False && 'String Value' -> false */}
{this.state.hasLoginFailed && <div>Invalid Login</div>}
{this.state.showSucessMessage && <div>Valid Login</div>}
UserName : <input type="text" name="username" value={this.state.username} onChange={this.handleChange} />
Password : <input type="password" name="password" value={this.state.password} onChange={this.handleChange} />
<button onClick={this.loginCheck}>Login</button>
</div>
)
}
}
export default ToDoApp
if I put localhost:3000/login -> Login Component should be displayed
if I put localhost:3000/welcome -> WelcomePage Component should be displayed
But now I am getting the blank page
import React from 'react';
import { BrowserRouter as Router, Routes, Route, } from "react-
router-dom";
import './App.css';
import Home from './components/Pages/Home';
function App() {
return (
<>
<Router>
<Routes>
<Route exact path='/' element={<Home/>}/>
</Routes>
</Router>
</>
)}
export default App;

React Router v4: custom PrivateRoute component keeps reloading

this is my first ever question so please spare my life.
I tried doing all the research I could and I've given up.
so basically I'm dealing with protected routes with react-router v4. After looking at Tyler Mcginnis' PrivateRoute, I thought I was on the right track but nope.
I can correctly set isAuthenticated: true with the requireUser function, but the PrivateRoute route component never renders. It always redirects to /login. After further investigation, I realized that somehow the page refreshes and therefore sets isAuthenticated back to false
also, I'm not using Redux.
OH, and any critics to my code is welcomed.
pls help
/App.js
class App extends Component {
constructor() {
super()
this.state = {
isAuthenticated: false,
user: {
username: ''
}
}
}
requireUser = (userData) => {
console.log('userData', userData);
if(userData) {
this.setState({
isAuthenticated: true,
user: {
username: userData.username
}
})
}
}
render() {
return (
<Router>
<div>
<Navbar />
<Route exact path='/' component={Landing} />
<Route path='/register' component={Register} />
<Route path='/login' render={(props) => {
return <Login {...props} requireUser={this.requireUser} />
}} />
<PrivateRoute path='/search' component={SearchBar} auth={this.state.isAuthenticated} />
</div>
</Router>
);
}
}
export default App;
/PrivateRoute.js
import React from 'react'
import { Route, Redirect } from 'react-router-dom'
const PrivateRoute = ({ component: Component, auth, path, ...rest}) => {
return <Route {...rest} path='/search' render={(props) => {
console.log(auth);
if(auth) {
return (
<Component {...props} />
)
} else {
return (
<Redirect to='/login' />
)
}
}} />
}
export default PrivateRoute
EDIT: added in my Login component
UPDATE: I ended up adding this.props.history.push('/search) to my handleOnSubmit function
/Login.js
import React, { Component } from 'react'
import axios from 'axios'
import jwt_decode from 'jwt-decode'
class Login extends Component {
constructor(props) {
super(props)
this.state = {
email: '',
password: '',
}
}
handleOnChange = (e) => {
this.setState({
[e.target.name]: e.target.value
})
}
handleOnSubmit = (e) => {
// prevent page refresh
e.preventDefault()
// destructure state
const { email, password } = this.state
// assign to userData
const userData = { email, password }
// axios post /api/users/login
axios
.post('/api/users/login', userData)
.then((response) => {
// destructure
const { token } = response.data
const decoded = jwt_decode(token)
this.props.requireUser(decoded)
})
.catch((error) => {
console.log(error);
})
}
render() {
return (
<section className="section">
<div className="container">
<form>
<div className="field">
<label className="label">Email</label>
<div className="control">
<input
type="email"
placeholder="email"
className="input"
name='email'
onChange={this.handleOnChange}
/>
</div>
</div>
<div className="field">
<label className="label">Password</label>
<input
type="password"
placeholder="password"
className="input"
name='password'
onChange={this.handleOnChange}
/>
</div>
<div className="field">
<div className="control">
<button
onClick={this.handleOnSubmit}
type="submit"
className="button is-primary"
>Log In</button>
</div>
</div>
</form>
</div>
</section>
)
}
}
export default Login
You code looks sound. The issue is that when you manually change the address bar to /search, the browser will be refreshed. There is no way around that.
You could alternatively use a Link component with a to prop value of '/search' that your user can use to navigate to the search, or you could programmatically change the path with the history object.
this.props.history.push('/search');

Categories