I have created a e Commerce App in react. As you can see from the screenshot below, that when I click on the Apparels->Girls->Shoes , the data is not displayed in the screen.
So first, in the index.js file, I have set the BrowserRouter and created a component Main which holds all my other components.
index.js
import React from "react";
import ReactDOM from "react-dom";
import Main from "./Main";
import "./index.css";
import 'bootstrap/dist/css/bootstrap.css';
import {Route, NavLink, BrowserRouter} from 'react-router-dom';
ReactDOM.render((
<BrowserRouter>
<Main/>
</BrowserRouter>
)
,
document.getElementById("root")
);
After this I have created Main.js, where I have created components for Navigation and PLPMenu( which should display after clicking on the Girls->Shoes). Also in the Main.js, I have set the switch and Route paths
Main.js
import React, { Component } from "react";
import 'bootstrap/dist/css/bootstrap.min.css';
import { Route, Switch } from 'react-router-dom';
import Navigation from "./components/topNavigation";
import Footer from "./components/Footer";
import Banner from "./components/Banner";
import PLPMenu from "./components/PLPMenu";
import PDP from "./components/PDP";
import Home from "./components/Home";
class Main extends Component {
render() {
return (
<div>
<Navigation />
<Switch>
<Route exact path="/" component={Home} />
<Route path="Apparel/Girls/:id" component={PLPMenu}/>
<Route path="/PDP" component={PDP} />
<Route path="/Banner" component={Banner} />
<Route path="/Footer" component={Footer} />
</Switch>
</div>
)
}
}
export default Main;
In the topNavigation.js, I'm displaying the first level of categories like Apparel, Electronics, Grocery etc. Also, I have created, a component SubMenu for displaying the second level of categories like Girls, Boys, Women etc.
topNavigation.js
import React, { Component } from 'react';
import axios from 'axios';
import SubMenu from './subMenu';
class Navigation extends Component {
state = {
mainCategory: []
}
componentDidMount() {
axios.get('http://localhost:3030/topCategory')
.then(res => {
console.log(res.data.express);
this.setState({
mainCategory: res.data.express.catalogGroupView
})
})
}
render() {
const { mainCategory } = this.state;
return mainCategory.map(navList => {
return (
<ul className="header">
<li key={navList.uniqueID}>
<a className="dropbtn ">{navList.name} </a>
<ul className="dropdown-content">
<SubMenu below={navList.catalogGroupView} />
</ul>
</li>
</ul>
)
})
}
}
export default Navigation;
subMenu.js
In the submenu.js, I have created one more component SubListMenu for displaying the inner categories like Shoes, Pants, Skirts, Tops etc.
import React, { Component } from 'react';
import SubListMenu from './subListMenu';
class SubMenu extends Component {
render() {
const { below } = this.props;
return below.map(sub => {
return (
<React.Fragment>
<li key={sub.uniqueID}>
<a>{sub.name}</a>
{
<ul className="sub-menu">
{sub.catalogGroupView !== undefined && <SubListMenu id={sub.uniqueID} subBelow={sub.catalogGroupView} />}
</ul>
}
</li>
</React.Fragment>
)
})
}
}
export default SubMenu;
subListMenu.js
import React, { Component } from 'react';
import {Link} from 'react-router-dom';
class SubListMenu extends Component {
render() {
const { subBelow, id } = this.props;
console.log(subBelow)
return(
<React.Fragment>
{subBelow && subBelow.map(subl => {
return (
<li key={subl.uniqueID}><Link to = {`Apparel/Girls/${subl.name}/${ subl.uniqueID }`}>{subl.name}</Link></li>
)
})
}
</React.Fragment>
)
}
}
export default SubListMenu;
As you can see from my subListMenu.js code, that I have set the Link to PLPMenu.js. But in my case it's not happening. Also, the part Apparel/Girls in the Link, I have hard coded which i'm not able to make it dynamic.
PLPMenu.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
class PLPMenu extends Component {
state = {
shoeCategory: []
}
componentDidMount() {
let pathname= this.props.match.params.id
console.log(pathname)
axios.get(`http://localhost:3030/${pathname}`)
.then(res => (res.json()))
.then(data => {
this.setState({
shoeCategory: data.express.catalogEntryView
})
});
}
render() {
const { shoeCategory } = this.state;
const picUrl = 'https://149.129.128.3:8443'
return (
<div>
<div className="container">
<div className="row">
{
shoeCategory && shoeCategory.map(shoeList => (
<div className="col-md-4">
<h2 key={shoeList.uniqueID}></h2>
<img src={picUrl + shoeList.thumbnail} />
<Link to="/PDP"><p className="pdp">{shoeList.name}</p></Link>
<p>Price : {shoeList.price[0].value} {shoeList.price[0].currency}</p>
</div>
))
}
</div>
</div>
</div>
)
}
}
export default PLPMenu;
For fetching the data, I have used a node server.
server.js
const express = require('express');
const cors = require('cors');
const Client = require('node-rest-client').Client;//import it here
const app = express();
app.use(cors());
app.get('/topCategory', (req, res) => {
var client = new Client();
// direct way
client.get("http://149.129.128.3:3737/search/resources/store/1/categoryview/#top?depthAndLimit=-1,-1,-1,-1", (data, response) => {
res.send({ express: data });
});
});
app.get('/GirlShoeCategory', (req, res) => {
var client = new Client();
// direct way
client.get("http://149.129.128.3:3737/search/resources/store/1/productview/byCategory/10015", (data, response) => {
res.send({ express: data });
});
});
const port = 3030;
app.listen(port, () => console.log(`Server running on port${port}`));
I don't know where my code is getting wrong. Maybe I feel that from the node server, there is a mismatch with the reactjs routes, for which only in the url, it's displaying the link but not the contents. Can someone please give me an insight on this. My console browser window:
for this issue
In the PLPMenu.js page, I'm trying to fetch the data. But all I'm getting is this undefined.
componentDidMount() {
let pathname= this.props.match.params.id
console.log(this.props.match.params.id)
axios.get(`http://localhost:3030/${pathname}`)
.then(res => {return res.json();})
.then(data => {
this.setState({
shoeCategory: data.express.catalogEntryView
})
});
}
try this it will solve undefined issue.
I believe you have to take id from subBelow instead this.props.id.
so change the code like this.
<li key={subl.uniqueID}><Link to = {`Apparel/Girls/${ subl.uniqueID }`}>{subl.name}</Link></li>
The reason you get undefined in URL bar because you are not passing the unique id from SubMenu down to SubListMenu component.
What you need to do is
SubMenu.js
import React, { Component } from 'react';
import SubListMenu from './subListMenu';
class SubMenu extends Component {
render() {
const { below } = this.props;
return below.map(sub => {
return (
<React.Fragment>
<li key={sub.uniqueID}>
<a>{sub.name}</a>
{
<ul className="sub-menu">
{sub.catalogGroupView !== undefined && <SubListMenu id={sub.uniqueID} subBelow={sub.catalogGroupView} />}
</ul>
}
</li>
</React.Fragment>
)
})
}
}
export default SubMenu;
SubListMenus.js
import React, { Component } from 'react';
import {Link} from 'react-router-dom';
class SubListMenu extends Component {
render() {
const { subBelow, id } = this.props;
console.log(subBelow)
return(
<React.Fragment>
{subBelow && subBelow.map(subl => {
return (
<li key={subl.uniqueID}><Link to = {`Apparel/Girls/${ id }`}>{subl.name}</Link></li>
)
})
}
</React.Fragment>
)
}
}
export default SubListMenu;
Regarding below issue You need to do res.json() and in next .then get the data
In the PLPMenu.js page, I'm trying to fetch the data. But all I'm getting is this undefined.
Do this
componentDidMount() {
let pathname= this.props.match.params.id
console.log(this.props.match.params.id)
axios.get(`http://localhost:3030/${pathname}`)
.then(res => (res.json()))
.then(data => {
this.setState({
shoeCategory: data.express.catalogEntryView
})
});
}
Edit:
Add below condition in PLPMenu component
{shoeCategory && shoeCategory.map(shoeList => (
Related
I am currently busy working on a personal project with a dashboard using NextJS, which I believe allows me to learn NextJS and the fundementals of typescript. I am trying to work out how to set a welcome message if a response sent back from the server is set to True, I did manage to code this in, but I got cannot set headers after they are sent to the client.
My entire code file for the dashboard is the following snippet:
import styles from "./index.module.css";
import { type NextPage } from "next";
import Head from "next/head";
import Link from "next/link";
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import NavDropdown from 'react-bootstrap/NavDropdown';
import { signIn, signOut, useSession } from "next-auth/react";
import Image from 'react-bootstrap/Image'
import Router from "next/router";
import { useEffect, useState } from "react";
import { library } from '#fortawesome/fontawesome-svg-core'
import { faHouse, fas, faServer } from '#fortawesome/free-solid-svg-icons'
import "#fortawesome/fontawesome-svg-core/styles.css";
import { Offline, Online } from "react-detect-offline";
import { config } from "#fortawesome/fontawesome-svg-core";
// Tell Font Awesome to skip adding the CSS automatically
// since it's already imported above
config.autoAddCss = false;
{/* The following line can be included in your src/index.js or _App.js file*/}
import 'bootstrap/dist/css/bootstrap.min.css';
library.add(fas, faServer, faHouse)
// import the icons you need
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
const Protected: NextPage = () => {
const { status, data } = useSession()
const { data: sessionData2 } = useSession();
useEffect(() => {
if (status === "unauthenticated") Router.replace("/auth/signin");
}, [status]);
// const isBreakpoint = useMediaQuery(768)
// return (
// <div>
// { isBreakpoint ? (
// <div>
// <HamburgerMenu />
// </div>
// ) : (
// <div>
// <FullMenu />
// </div>
// )
if (status === "authenticated")
return (
<><Navbar bg="dark" expand="lg" variant="dark" className="justify-content-end flex-grow-1 pe-3">
<Container>
<Navbar.Brand href="#home" style={{ fontSize: '25px' }}><strong>Litika.</strong> </Navbar.Brand>
{/* <Navbar.Toggle aria-controls="basic-navbar-nav" /> */}
<Navbar.Collapse id="basic-navbar-nav" className={styles.rightNavbar}>
<Nav className={styles.rightNavbar}>
<Nav.Link href="#home" className={styles.body}><FontAwesomeIcon icon={faHouse} /></Nav.Link>
<Nav.Link href="#link" className={styles.body}>Link</Nav.Link>
<NavDropdown className={styles.body} title={<Image
src={sessionData2 ? `https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_640.png` : 'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_640.png'}
roundedCircle
style={{ width: '30px' }} />}
id="basic-nav-dropdown">
<NavDropdown.Item href="#action/3.1" onClick={sessionData2 ? () => void signOut() : () => void signIn()}>
{sessionData2 ? "Sign out" : "Sign in"}
</NavDropdown.Item>
<NavDropdown.Item href="#action/3.2">
Another action
</NavDropdown.Item>
<NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item>
<NavDropdown.Divider />
<NavDropdown.Item href="#action/3.4">
Separated link
</NavDropdown.Item>
</NavDropdown>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
<div className={styles.connectivityStatus}>
<br></br>
<div className={styles.connectivityStatusBox}>
<Online>š¢ You are connected to the internet.</Online>
<Offline>š“ You are not connected to the internet.</Offline>
</div>
<WelcomeContainer />
</div>
<main className={styles.main}>
<h1 className={styles.title}>
Litika. </h1>
<div className={styles.container}>
<div className={styles.cardRow}>
<div className={styles.card}>
<h1 className={styles.cardTitle}><FontAwesomeIcon icon={faServer} /> HELLO!</h1>
<p className={styles.cardText}>How are you? I am under the water.</p>
</div>
</div>
</div>
</main>
<main className={styles.main2}>
<div className={styles.container}>
</div>
</main>
</>
);
return (
<>
<main className={styles.main}>
<div className={styles.container}>
<h1 className={styles.title}>
Loading the Dashboard.
</h1>
</div>
</main>
<main className={styles.main2}>
<div className={styles.container}>
<h1 className={styles.title}>
</h1>
</div>
</main>
</>
);
};
export default Protected;
const WelcomeContainer: React.FC = () => {
const { data: sessionData } = useSession();
var [welcomeMessage, setWelcomeMessage] = useState(null);
const payload = JSON.stringify({
email: sessionData.user?.email,
});
fetch('/api/userService/isuserwelcome', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: payload
})
.then(response => response.json())
.then(data => {
console.log(data);
if (data === true) {
setWelcomeMessage(
<div className={styles.welcomeContainer}>
<h1>Welcome to the Los pollos hermanos family.</h1>
</div>
);
}
})
.catch(error => {
console.error(error);
});
return (
<>
{welcomeMessage}
</>
);
};
The code for the IsUserWelcome API Route is the following:
import type { NextApiRequest, NextApiResponse } from 'next';
import { PrismaClient } from '#prisma/client';
const prisma = new PrismaClient();
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
try {
const { email } = req.body;
const cliresponse = await prisma.user.findFirst({
where: {
email,
},
});
console.log(cliresponse.newUser)
if (cliresponse.newUser == true) {
res.status(200).json(cliresponse.newUser)
}
res.status(200).json({ cliresponse });
} catch (err) {
console.log(err)
res.status(500).json({ error: err});
}
}
I have identified the issue to be coming from the WelcomeContainer Functional Component and do understand that NextJS & React are dynamic, which will lead to updates through the DOM. However, I haven't really tried anything yet to fix this issue because nothing from doing a simple Google search could lead me to fix this issue, so any guidance & help will be appreciated!
The parts that are different in this question is that it pertains to react and NextJS in general, not express.
You are sending a response twice, after a response is send you should return from the function.
import type { NextApiRequest, NextApiResponse } from 'next';
import { PrismaClient } from '#prisma/client';
const prisma = new PrismaClient();
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
try {
const { email } = req.body;
const cliresponse = await prisma.user.findFirst({
where: {
email,
},
});
console.log(cliresponse.newUser)
if (cliresponse.newUser == true) {
res.status(200).json(cliresponse.newUser)
return; // you need to return here so the code below doesn't get executed
}
res.status(200).json({ cliresponse });
} catch (err) {
console.log(err)
res.status(500).json({ error: err});
}
}
I have a route /courses and when I do search for courses from the frontend(ReactJs) it takes me to this URL http://localhost:3001/courses/search?searchQuery=introducton but when I again click on courses button(that is on my navbar), it takes me to /courses but It doesn't show all the courses, it only shows the searched query that I got from the above query. Every time I need to refresh the page to get all the courses.
Courses.js file
import React, { useState } from "react"
import CourseHeader from "./CourseHeader"
import CoursesList from "./CoursesList"
import FilterCourse from "./FilterCourse"
import Filtertech from "./Filtertech"
import { useDispatch, useSelector } from "react-redux"
import { useHistory } from "react-router"
import { getCoursesBySearch } from "../../actions/courses"
const Courses = () => {
const dispatch = useDispatch()
const [search, setSearch] = useState("")
const history = useHistory()
const searchCourses = () => {
if (search.trim()) {
dispatch(getCoursesBySearch({ search }))
history.push(`/courses/search?searchQuery=${search || "none"}`)
} else {
history.push("/courses")
}
}
const handleKeyPress = (e) => {
if (e.keyCode === 13) {
searchCourses()
}
}
const courses = useSelector((state) => state.courses)
return (
<div className="row-start-2 row-end-3 col-start-1 col-end-2 mx-auto w-full max-w-5xl ">
<div className="grid grid-cols-layout-course gap-x-3">
<div>
<FilterCourse />
<Filtertech />
</div>
<div>
<CourseHeader
handleKeyPress={handleKeyPress}
setSearch={setSearch}
search={search}
/>
<CoursesList courses={courses} />
</div>
</div>
</div>
)
}
export default Courses
CourseList.js
import React from "react"
import CourseCard from "./CourseCard"
const CoursesList = ({ courses }) => {
return (
<div className="">
{courses && courses.map((course) => <CourseCard data={course} key={course._id} />)}
</div>
)
}
export default CoursesList
App.js
import "./App.css"
import "./assets/output.css"
import { BrowserRouter as Router, Switch, Route } from "react-router-dom"
import Navbar from "./components/layouts/Navbar"
import Courses from "./components/courses/Courses"
import { useEffect } from "react"
import { getCourses } from "./actions/courses"
function App() {
const dispatch = useDispatch()
useEffect(() => {
dispatch(getCourses())
}, [dispatch])
return (
<Router>
<div className="App min-h-screen grid grid-rows-layout-desktop grid-cols-layout-desktop gap-10">
<Navbar />
<Switch>
<Route path="/courses">
<Courses />
</Route>
</Switch>
<Footer />
</div>
</Router>
)
}
export default App
Anyone please help me with this
I tried to create an authentication website with Firebase using email and password. I can't even load the Login page.
Here's Auth.js
import React, { useState, useEffect} from "react";
import { auth } from './config'
import { onAuthStateChanged } from "firebase/auth";
export const AuthContext = React.createContext();
export const AuthProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null);
useEffect(() => {
onAuthStateChanged(auth, (user) => {
setCurrentUser(user);
})
}, [])
return (
<AuthContext.Provider value={{currentUser}}>
{children}
</AuthContext.Provider>
)
}
And this is Login.js
import React, {useContext ,useState } from "react";
import Form from "react-bootstrap/Form";
import Button from "react-bootstrap/Button";
import "./Login.css";
import { auth } from './config'
import { signInWithEmailAndPassword } from "firebase/auth";
import { AuthContext } from "./Auth";
import { useHistory } from "react-router-dom";
const Login = () => {
let history = useHistory();
const handleSubmit = (event) => {
event.preventDefault();
const { email, password } = event.target.elements;
signInWithEmailAndPassword(auth, email.value, password.value)
.then((userCredential) => {
const user = userCredential.user;
console.log(user.uid);
})
.catch((error) => {
console.log(error.massage);
});
}
const currentUser = useContext(AuthContext);
if(currentUser) {
return history.push('/dashboard');
}
return (
<div className="Login">
<h1>Login</h1>
<Form onSubmit={handleSubmit}>
//Login Form
</Form>
</div>
);
}
export default Login
And DashBoard.js
import React, {useContext} from 'react'
import { AuthContext } from './Auth'
import { auth } from './config'
import { signOut } from 'firebase/auth'
import { useHistory } from "react-router-dom";
const DashBoard = () => {
const currentUser = useContext(AuthContext);
let history = useHistory();
if(!currentUser) {
return history.push('/login');
}
const signOutFunc = () => {
signOut(auth)
}
return (
<div>
<div className='container mt-5'>
<h1>Welcome</h1>
<h2>If you see this you are logged in.</h2>
<button className='btn btn-danger' onClick={signOutFunc}>Sign Out</button>
</div>
</div>
)
}
export default DashBoard;
Lastly App.js
import { BrowserRouter as Router, Route, Switch} from 'react-router-dom'
import Login from './Login'
import DashBoard from './DashBoard';
import { AuthProvider } from './Auth'
function App() {
return (
<AuthProvider>
<Router>
<Switch>
<Route exact path="/login" component={Login} />
<Route exact path="/dashboard" component={Dashboard} />
</Switch>
</Router>
</AuthProvider>
);
}
export default App;
When I open /login, it would send me to /dasgboard immediately. If I typed /login again it gives me this error
Error: Login(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.
I can't figure it out what's wrong with it. Please help me.
Thank you
You have multiple places in your code where you return history.push('/dashboard'); or another path. You should return there a null:
if(!currentUser) {
history.push('/login');
return null
}
But there is no request to the server. Is there any mistakes in this code?
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom'
import axios from 'axios';
import { useSelector, useDispatch } from 'react-redux';
import { listProducts } from '../actions/productActions';
function HomeScreen(props) {
const productList = useSelector(state => state.productList);
const { products, loading, error } = productList;
const dispatch = useDispatch();
useEffect(() => {
const fetchData = async () =>{
dispatch(listProducts());
}
return () =>{
//
};
}, [])
return loading ? <div>Loading...</div> :
error ? <div>{error}</div> :
<ul className="products">
{
products.map(product =>
<li key={product._id}>
<div className="product">
<Link to={'/product/' + product._id}>
<img className="product-image" src={product.image} alt="product"/>
</Link>
<div className="product-name">
<Link to= {'/product/' + product._id}> {product.name} </Link>
</div>
<div className="product-brand">{product.brand}</div>
<div className="product-price">Rs.{product.price}</div>
<div className="product-rating">{product.rating} Stars ({product.numReivews}Reviews)</div>
</div>
</li>)
}
</ul>
}
export default HomeScreen;
As you see in following screenshot, there is no request to the server.Does anyone have idea about this matter?
You're not calling the fetchData() function. Instead you've only declared it inside useEffect.
So instead of
useEffect(() => {
const fetchData = async () =>{
dispatch(listProducts());
};
return () =>{
//
};
}, [])
you can just write
useEffect(() => {
dispatch(listProducts());
return () =>{
//
};
}, [])
This might not be the full solution as, for example, I don't know what listProducts() does but certainly it is a part of the solution.
Im developing an app where I need to login and after click tha Login button I need to redirect to another view that is in another layout, I've tried using this.props.history.push("/Inicio") to redirect when the Login is succesful. In this case this is the path.
{
path: "/Inicio",
name: "Inicio",
component: Inicio,
layout: "/admin"
},
This is the entire code
import React, { Component } from "react";
import {
Grid,
Col
} from "react-bootstrap";
import { Card } from "components/Card/Card.jsx";
import { FormInputs } from "components/FormInputs/FormInputs.jsx";
import Button from "components/CustomButton/CustomButton.jsx";
class Login extends Component {
constructor(props) {
super(props)
this.state = {
users: [],
user: '',
pass: '',
msg: '',
apiResponse:''
}
this.logChange = this.logChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this)
}
handleSubmit(event) {
event.preventDefault()
var data = {
user: this.state.user,
pass: this.state.pass,
msg: this.state.msg,
apiResponse: this.state.apiResponse
}
console.log(data)
fetch("http://localhost:9000/log/Login", {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}).then(function(response) {
if (response.status >= 400) {
throw new Error("Bad response from server");
}
return response.json();
}).then((data) => {
if(data == "success"){
console.log(data)
this.setState({users: data});
this.props.history.push("/Inicio");
window.location.reload();
}
else{
if(data == 'El usuario o la contraseƱa no coinciden'){
this.setState({ apiResponse: data })
}
}
}).catch(function(err) {
console.log(err)
});
}
logChange(e) {
this.setState({[e.target.name]: e.target.value});
}
render() {
return (
<div className="content">
<p class="col-md-4"></p>
<Grid >
<Col md={5}>
<Card
title="Login"
content={
<form method='POST' onSubmit= {this.handleSubmit}>
<p class="col-md-2"></p>
<FormInputs
ncols={["col-md-7"]}
properties={[
{
label: "Usuario",
type: "text",
bsClass: "form-control",
placeholder: "Usuario",
maxlength: 20 ,
name: "user",
onChange: this.logChange
}
]}
/>
<p class="col-md-2"></p>
<FormInputs
ncols={["col-md-7"]}
properties={[
{
label: "ContraseƱa",
type: "password",
bsClass: "form-control",
placeholder: "ContraseƱa",
maxlength: 20,
name: "pass",
onChange: this.logChange
}
]}
/>
<p >{this.state.apiResponse}</p>
<br/>
<br/>
<Button bsStyle="info" pullRight fill type="submit">
Login
</Button>
<Button bsStyle="info" pullLeft fill type="submit">
Olvide mi ContraseƱa
</Button>
</form>
}
/>
</Col>
</Grid>
</div>
);
}
}
export default Login;
but in the handleSubmit() everything is working fine except for this.props.history.push("/Inicio") because it doesn't do anything.
The index.js code
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "./assets/css/animate.min.css";
import "./assets/sass/light-bootstrap-dashboard-react.scss?v=1.3.0";
import "./assets/css/demo.css";
import "./assets/css/pe-icon-7-stroke.css";
import AdminLayout from "layouts/Admin.jsx";
import LoginLayout from "layouts/LoginLayout.jsx";
import EfoodLayout from "layouts/EFoodLayout.jsx";
ReactDOM.render(
<BrowserRouter>
<Switch>
<Route path="/admin" render={props => <AdminLayout {...props} />} />
<Route path="/login" render={props => <LoginLayout {...props} />} />
<Route path="/Efood" render={props => <EfoodLayout {...props} />} />
<Redirect from="/" to="/login/Login" />
</Switch>
</BrowserRouter>,
document.getElementById("root")
);
LoginLayout
import React, { Component } from "react";
import { Route, Switch } from "react-router-dom";
import LoginNavbar from "components/Navbars/LoginNavbar";
import Footer from "components/Footer/Footer";
import routes from "routes.js";
class Login extends Component {
getRoutes = routes => {
return routes.map((prop, key) => {
if (prop.layout === "/login") {
return (
<Route
path={prop.layout + prop.path}
render={props => (
<prop.component
{...props}
handleClick={this.handleNotificationClick}
/>
)}
key={key}
/>
);
} else {
return null;
}
});
};
getBrandText = path => {
return "Bienvenido a E Food";
};
render() {
return (
<div className="wrapper">
<LoginNavbar
brandText={this.getBrandText(this.props.location.pathname)}
/>
<Switch>{this.getRoutes(routes)}</Switch>
<Footer />
</div>
);
}
}
export default Login;
I hope you can help me, and thanks to everyone who answer.
PD: If you need more from my code, please let me know.
Ok, since it's obvious the component you want to do the navigation in is a deeply nested component there are a couple options.
Prop Drilling (not recommended)
prop drilling
The cons of prop drilling is that if the right props aren't passed to begin with, or if any component along the way forgets to pass on props, then some child component won't receive what they need and it may be difficult to track down the what or why it's missing. It's more difficult to maintain as now any changes to this component necessitate needing to be concerned about every other component around it. Prop drilling is actually a react anti-pattern.
LoginLayout
Your LoginLayout component appears to consume a routes config object and dynamically render routes. It needs to pass on the route props it received from its parent. Any component between here and the Login where you want to use history.push would need to keep passing all the props down.
class Login extends Component {
getRoutes = routes => {
return routes.map((prop, key) => {
if (prop.layout === "/login") {
return (
<Route
path={prop.layout + prop.path}
render={props => (
<prop.component
{...props}
{...this.props} // <-- Pass on all props passed to this component
handleClick={this.handleNotificationClick}
/>
)}
key={key}
/>
);
} else {
return null;
}
});
};
...
render() {
return (
...
);
}
}
Use withRouter Higher Order Component (recommended)
withRouter
You can get access to the history objectās properties and the closest
<Route>'s match via the withRouter higher-order component. withRouter
will pass updated match, location, and history props to the wrapped
component whenever it renders.
import React, { Component } from "react";
import { withRouter } from 'react-router-dom'; // <-- import HOC
import { Grid, Col } from "react-bootstrap";
import { Card } from "components/Card/Card.jsx";
import { FormInputs } from "components/FormInputs/FormInputs.jsx";
import Button from "components/CustomButton/CustomButton.jsx";
class Login extends Component {
constructor(props) {
...
}
handleSubmit(event) {
event.preventDefault();
var data = {
user: this.state.user,
pass: this.state.pass,
msg: this.state.msg,
apiResponse: this.state.apiResponse
};
console.log(data);
fetch("http://localhost:9000/log/Login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
})
.then(function(response) {
if (response.status >= 400) {
throw new Error("Bad response from server");
}
return response.json();
})
.then(data => {
if (data == "success") {
console.log(data);
this.setState({ users: data });
this.props.history.push("/Inicio"); // <-- history prop should now exist
window.location.reload();
} else {
if (data == "El usuario o la contraseƱa no coinciden") {
this.setState({ apiResponse: data });
}
}
})
.catch(function(err) {
console.log(err);
});
}
logChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
render() {
return (
<div className="content">
...
</div>
);
}
}
export default withRouter(Login); // <-- decorate Login with HOC
Are you using react-router-dom to handle your routing ? If so, you can use the hooks to navigate.
import { useHistory } from "react-router-dom";
...
const history = useHistory()
...
history.push('/Inicio')
Note that this will only work with React version >= 16.8
The reason why your code is not working is because of the bindings.
When using this.props.history.push("/Inicio"), this refers to the function you're in, not to the Component history.
If you want to keep your code that way, you can simply turn your function into an arrow function:
.then((data) => {
if(data == "success"){
console.log(data)
self.setState({users: data});
**this.props.history.push("/Inicio")** // now this will be correct
**window.location.reload();** // no need, react handles the reload
}
else{
if(data == 'El usuario o la contraseƱa no coinciden'){
self.setState({ apiResponse: data })
}
}
Although, I'd strongly advise using the latest features of react (check the hooks, it's really useful).