Hey guys I did a project that simulates Netflix and I'm making it using react for the front end and Node.js express.js for the Back end. When I run the react code, the paths of each page are working. What I mean when I say "paths" is paths like "http://localhost:3000/" and "http://localhost:3000/login". However, when I start running the server-side code and then I refresh the page, I get this message: "Cannot GET /" or "Cannot GET /login". I think I have a problem about handling the GET request on my server, but my POST requests are handled pretty well.
I will provide you my home page code component and login page code component and server-side code, Also App component code and project file structure below:
(react code)home page:
import React,{useState} from 'react';
import PlayArrowIcon from '#mui/icons-material/PlayArrow';
import InfoIcon from '#mui/icons-material/Info';
import Header from './header.jsx';
import Footer from './footer.jsx';
import List from './list.jsx';
import axios from "axios";
import { useEffect } from 'react';
export default function Home(){
const[movies,SetMovies] = useState([]);
const[randomPoster,SetrandomPoster] = useState({});
const type="";
useEffect(()=>{
const fetch = async()=>{
await axios.get("https://api.themoviedb.org/3/movie/upcoming?api_key=c2ca0c1d4432e9a9db70a5b7154e2053").then(async data=> { const d = await data.data.results; SetMovies(d)}).catch(err => console.log(err));
}
fetch();
},[]);
const fetch2 = async()=>{
const index = Math.round(Math.random() * movies.length-1);
let r = movies[2];
const image = "https://image.tmdb.org/t/p/w500"+ r.backdrop_path
return {image :image, title: r.title, overview: r.overview}
}
const temp = fetch2();
temp.then(async res=>{
SetrandomPoster(res);
})
return(
<>
<Header/>
<div className='home'>
<div className='imgStuff'>
{type&&( <>
<div id='genre'>
<h1>{type}</h1>
<select >
<option value=""></option>
<option value=""></option>
<option value=""></option>
</select>
</div>
</>)}
<img className= "poster" src={randomPoster.image} alt="" />
<div className='texts'>
<div className='title'>
<h1>Watch {randomPoster.title}</h1>
<h3>{randomPoster.overview}</h3>
</div>
<div className='btns'>
<button className='Playbtn'><PlayArrowIcon id= "play"/>Play</button>
<button className='Infobtn'><InfoIcon id = "info"/>Info</button>
</div>
</div>
</div>
<List name="Popular"/>
<List name="Trending"/>
<List name="Comingup"/>
<List name="Playing now"/>
</div>
<Footer/>
</>
);
}
(react code)login page:
import React, { useState } from "react";
import LoginHeader from './LoginHeader';
export default function Login(){
// useState hook to store the input values
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const handlePost = () => {
fetch('http://localhost:3000/login', {
method: "POST",
headers: {
'Content-type': 'application/json'
},
body: {
username: username,
password: password
}
})
.then((response) => response.json())
.then((result) => {
console.log(result)
})};
return (
<>
<LoginHeader/>
<div className="login">
<div className="formContainer">
<form className="form" onSubmit={handlePost}>
<h2 className="textSginin">Sign in</h2>
<div >
<input className="username" type="text" onChange={(e) => setUsername(e.target.value)}/>
<input className ="password"type="password" onChange={(e) => setPassword(e.target.value)}/>
</div>
<div className="buttonContainer">
<input id="submit" type="submit" value={"login"}/>
<div className="spanFlex">
<div className="checkboxContainer">
<input id = "checkbox" type="checkbox"/>Remeber me?
</div>
<span id="help">Need help?</span>
</div>
</div>
</form>
<div className="signupAlert" >
<h2>New to Netflix? <span>Sign up now.</span></h2>
<p>This page is protected by Google reCAPTCHA to ensure you're not a bot. <span>Learn more.</span></p>
</div>
</div>
</div>
</>
);
}
server-side:
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.post("/login", (req,res)=>{
const username = req.body.username;
const password = req.body.password;
console.log(username +" "+ password);
res.status(200).send("ok");
})
app.listen(3000,()=>{
console.log("server connected on port 3000");
})
App component code
import '../style/App.css';
import { BrowserRouter as Router, Routes , Route } from "react-router-dom";
import Home from './home.jsx';
import Login from './login'
import React from 'react';
function App() {
return(
<div>
<Router>
<Routes >
<Route path="/" exact element={<Home/> } />
<Route path="/login" element={ <Login/>} />
</Routes >
</Router>
</div>
);
}
export default App;
Project file structure
GET method for different route(s) is not defined in server side. Or if you have defined please share that code too.
Below is just an example how you can define(if not defined already).
app.get("/login", (req,res)=>{
// logic
})
app.get("/", (req,res)=>{
// logic
})
I guess my mistake was running the react project and the server on the same port 3000, I have fixed that by running the server code on other port like 3001
Related
I'm creating a simple react application with 3 user roles. On the login page localhost:3000/login I have fields for username and password. Once those details are entered and the login button is clicked, the data is sent to the backend (running node js) and that data is used to query a MySql database. If the entered data matches a user in the database, the userId, name, password, and role is sent to the backend. This data is then sent to the front end. I can read the retrieved data from the front end and up to this point it works fine. However, when I'm trying to redirect a user according to the role, say the role is doctor and I want to redirect the user to localhost:3000/doctor , it goes to localhost:3000/doctor momentarily and switches to localhost:3000/login?. Shown below is the code for the login component.
import { useState } from "react";
import Axios from 'axios';
import { useNavigate } from 'react-router-dom'
import './login.css';
const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
let navigate = useNavigate()
const handleLogin = () => {
Axios.post("http://localhost:3001/login",
{
email: email,
password: password,
},
{
headers: {
'Content-Type': 'application/json'
}
}
)
.then((response) => {
console.log('response 1', response.data[0]['role'])
if (response.data[0]['role'] === 'doctor') {
navigate('/doctor');
}
});
};
return (
<div>
<form>
<h3>Electronic Prescription System</h3>
<h3>Login</h3>
<label>Email Address</label>
<input
className="inputs"
type="text"
placeholder="email"
onChange={(e) => {
setEmail(e.target.value)
}}
/>
<label>Password</label>
<input
className="inputs"
type="password"
placeholder="password"
onChange={(e) => setPassword(e.target.value)}
/>
<button onClick={handleLogin}>Log in</button>
</form>
</div>
)
};
export default Login;
If I remove all the code inside the handleLogin function and just have navigate('/doctor'); it redirects properly.
The routes are inside the Main component as shown below.
import React from 'react';
import { Routes, Route } from 'react-router-dom';
import Login from "./pages/Login/Login";
import Doctor from "./pages/Doctor/Doctor";
import Patient from "./pages/Patient/Patient";
import Pharmacy from "./pages/Pharmacy/Pharmacy";
const Main = () => {
return (
<Routes>
<Route path="login" element={<Login />} />
<Route path="doctor" element={<Doctor />} />
<Route path="patient" element={<Patient />} />
<Route path="pharmacy" element={<Pharmacy />} />
</Routes>
);
}
export default Main;
The Doctor Component:
import { HeaderPanel } from '../../components/headerPanel/headerPanel'
import { PrescribePanel } from '../../components/prescribePanel/prescribePanel'
import { PrescriptionsList } from '../../components/prescriptionsList/prescriptionsList'
import './styles.css';
export const Doctor = () => {
return (
<>
<HeaderPanel />
<div className='wrapper'>
<PrescribePanel />
<PrescriptionsList />
</div>
</>
);
}
export default Doctor
I'm using react-router-dom version 6.6.1 and the react version is 18.2.0.
Tried using a useEffect hook to capture the role changing and redirecting, but id did not work either.
What I suspect is happening here is that the "log in" button is submitting the form which takes the default form action and reloads the page, the current route path being "/login". button elements have a type="submit" attribute value by default.
To resolve I'd suggest attaching handleLogin to the form element's onSubmit event handler and calling preventDefault on the onSubmit event object to prevent submitting the form and prevent reloading the page. This should allow the authentication logic to complete as expected.
Try to get yourself in the habit of being specific with the button element's type attribute.
const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const navigate = useNavigate();
const handleLogin = (e) => { // <-- onSubmit event object
e.preventDefault(); // <-- don't take form action
Axios.post(
"http://localhost:3001/login",
{ email, password },
{
headers: {
'Content-Type': 'application/json'
}
}
)
.then((response) => {
if (response.data[0]['role'] === 'doctor') {
navigate('/doctor');
}
});
};
return (
<div>
<form onSubmit={handleLogin}> // <-- form onSubmit event handler
<h3>Electronic Prescription System</h3>
<h3>Login</h3>
<label>
Email Address
<input
className="inputs"
type="text"
placeholder="email"
onChange={(e) => setEmail(e.target.value)}
/>
</label>
<label>
Password
<input
className="inputs"
type="password"
placeholder="password"
onChange={(e) => setPassword(e.target.value)}
/>
</label>
<button type="submit"> // <-- be specific with button type
Log in
</button>
</form>
</div>
);
};
export default Login;
I would like to know why my "topbar" is duplicated when I only want one. And it's since I did my import of the user image via axios and added the .map in the return. I really don't understand why if someone could help me that would be nice. Thanks in advance
import "./topbar.css"
import { Search } from '#mui/icons-material'
import { useState, useEffect, Fragment } from 'react'
import axios from "axios"
function Home() {
const [user, setPosts] = useState([])
useEffect(() => {
console.log("chargement ok")
const fetchData = async () => {
const result = await axios.get(
'http://localhost:4200/api/user/')
setPosts(result.data)
}
fetchData();
}, [])
return (
<Fragment>
{ user
? user.map((users,topbar) => ( <div key={topbar} className="topBarContainer">
<div className="topBarLeft">
<span className="logo">Groupomania</span>
</div>
<div className="topBarCenter">
<div className="searchBar">
<Search className="searchIcon" />
<input placeholder="Vous cherchez quelque chose ?" className="searchInput" />
</div>
</div>
<div className="topBarRight">
<div className="topBarLinks">
<span className="topBarLink">Page d'acceuil</span>
<span className="topBarLink">Deconnexion</span>
</div>
<img src={users.picture} alt="Photo de profil de l'utilisateur" className="topBarImg" />
</div>
</div>))
: (<p></p>)
}
</Fragment>
)
}
export default Home
I'm not sure why, but it may be because of your key.
Some patterns to fix first:
const [user, setPosts] = useState([]) -> const [posts, setPosts] = useState([])
you don't have to use the word Fragment: -> <>
Normally in a .map params are used like this posts.map((post, index) => ...)
posts ? post.map(...) : null
Edit: of course you have to remove your topbar from your .map(...)
Now try with a better key than "topbard" that is the index in the array ... try post.id that should be uniq
Edit solution:
import "./topbar.css";
import { Search } from "#mui/icons-material";
import { useState, useEffect, Fragment } from "react";
import axios from "axios";
function Home() {
const [user, setUser] = useState();
useEffect(() => {
console.log("chargement ok");
const fetchData = async () => {
const result = await axios.get("http://localhost:4200/api/user/");
setUser(result.data);
};
fetchData();
}, []);
return (
<div className="topBarContainer">
<div className="topBarLeft">
<span className="logo">Groupomania</span>
</div>
<div className="topBarCenter">
<div className="searchBar">
<Search className="searchIcon" />
<input
placeholder="Vous cherchez quelque chose ?"
className="searchInput"
/>
</div>
</div>
<div className="topBarRight">
<div className="topBarLinks">
<span className="topBarLink">Page d'acceuil</span>
<span className="topBarLink">Deconnexion</span>
</div>
{user && <img
src={user.picture}
alt="Photo de profil de l'utilisateur"
className="topBarImg"
/>}
</div>
</div>
);
}
export default Home;
As the map is rendering the topbar for every user, you get as many topbars as there are users.
The map function should be inside the top bar container div.
<div key={key} className="topBarContainer">
{ user.map(...) }
</div>
This is because your are making the topbar inside the loop,So you are getting a topbar per user.
I have been struggling with this for some time and I am not sure how to solve the issue.
Basically, I am trying to render some components onto my Index page, this is my code below:
App.js
import Index from "./Components/Index"
import axios from "axios"
export default function App() {
const [movieList, setMovieList] = React.useState([])
let featured = []
let coming = []
let showing = []
React.useEffect(() => {
console.log("Ran App Effects")
axios.get(`API_CALL_TO_GET_LIST_OF_MOVIES`)
.then(res =>{
setMovieList(res.data)
})
}, [])
return(
<div>
{movieList.map(movie =>{
if(movie.status === 'featured'){
featured.push(movie.api_ID)
} else if (movie.status === 'upcoming'){
coming.push(movie.api_ID)
} else{
showing.push(movie.api_ID)
}
})}
<Index featured={featured} coming={coming} showing={showing}/>
</div>
)
}
In the code above I am receiving an array of Objects and based on what is in their status I am putting them in some empty arrays and sending them as props into my Index component.
This is what my index component looks like:
import React from "react"
import Header from "./Header"
import Footer from "./Footer"
import MovieCard from "./MovieCard"
import axios from "axios"
export default function Index(props) {
const [featuredMovies, setFeaturedMovies] = React.useState([])
const [comingMovies, setComingMovies] = React.useState([])
//const featured = [419704,338762,495764,38700,454626,475557]
//const coming = [400160,514847,556678,508439,524047,572751]
React.useEffect(() => {
console.log("Ran Effect")
axios.all(props.featured.map(l => axios.get(`API_CALL_TO_GET_SPECIFIC_MOVIE/${l}`)))
.then(axios.spread(function (...res){
setFeaturedMovies(res)
}))
.catch((err) => console.log(err))
axios.all(props.coming.map(l => axios.get(`API_CALL_TO_GET_SPECIFIC_MOVIE/${l}`)))
.then(axios.spread(function (...res){
setComingMovies(res)
}))
.catch((err) => console.log(err))
}, [])
return(
<body>
<Header />
<section className="home">
<div className="container">
<div className="row">
<div className="col-12">
<a className="home__title">FEATURED MOVIES</a>
</div>
{ featuredMovies.map(movie =>{
return <MovieCard movie={movie} featured={true} />
}) }
{console.log(props.featured)}
</div>
</div>
</section>
<section className="home">
<div className="container">
<div className="row">
<div className="col-12">
<a className="home__title">COMING SOON</a>
</div>
{ comingMovies.map(movie =>{
return <MovieCard movie={movie} featured={false} />
})}
</div>
</div>
</section>
<Footer/>
</body>
)
}
The issue I am running into is, whenever I run the app for the first time it works fine but then when I hit the refresh button the components do not render anymore
The only time it re-renders when I refresh the page is when I uncomment,
//const featured = [419704,338762,495764,38700,454626,475557]
//const coming = [400160,514847,556678,508439,524047,572751]
and replace the props.featured.map and props.coming.map with featured.map and coming.map hence using the hard coded values and not the values passed in from the props.
Any help with this would be much appreciated as I am completely stuck and currently pulling my hair out.
I took the liberty to tinker with your code. In the example below I've rearranged the data into three sets with the help of useMemo and by checking the status property of each movie. It is important to keep any data related logic outside of the render logic.
I also moved around some of your HTML structure. You were outputting a <body> tag inside of a <div>. The outer layer should be in control of the outer HTML structure, so I moved that HTML to the App component.
import { useState, useEffect, useMemo } from 'react'
import Header from "./Components/Header"
import Footer from "./Components/Footer"
import Index from "./Components/Index"
import axios from "axios"
export default function App() {
const [movieList, setMovieList] = useState([])
const featuredMovies = useMemo(() => {
return movieList.filter(({ status }) => status === 'featured');
}, [movieList]);
const upcomingMovies = useMemo(() => {
return movieList.filter(({ status }) => status === 'upcoming');
}, [movieList]);
const showingMovies = useMemo(() => {
return movieList.filter(({ status }) => status !== 'featured' && status !== 'upcoming');
}, [movieList]);
useEffect(() => {
axios.get(`API_CALL_TO_GET_LIST_OF_MOVIES`)
.then(res =>{
setMovieList(res.data)
})
}, [])
return (
<body>
<Header />
<Index data={featuredMovies} title="Featured Movies" featured={true} />
<Index data={upcomingMovies} title="Coming Soon" />
<Index data={showingMovies} title="Showing Now" />
<Footer/>
</body>
)
}
Since we now have three sets of movies (featured, upcoming, and playing) it would also make sense to have three components that handle those data sets instead of having one that handles multiple. Each Index component gets its own data set and other props to render the movies within it.
import MovieCard from "./MovieCard"
export default function Index({ data, title, featured = false }) {
return (
<section className="home">
<div className="container">
<div className="row">
<div className="col-12">
<a className="home__title">{title}</a>
</div>
{data.map(movie => {
return <MovieCard movie={movie} featured={featured} />
})}
</div>
</div>
</section>
);
}
I´m using a npm of inputs plus react hooks but when i submit the data i get undefined values in my console. I tried using the default input tags and works fine, the data i send shows perfectly. Any suggestions? is it possible to work with this NPM and react hook form or should i use the default data (Something that i don´t really like to do)
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
import Nav from "./Navbar";
import Footer from "./Footer";
import { FormField } from 'react-form-input-fields';
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { useForm } from "react-hook-form";
import { faEye,faEyeSlash } from '#fortawesome/free-solid-svg-icons';
import 'react-form-input-fields/dist/index.css';
function Login() {
const {register, handleSubmit } = useForm();
const eye = <FontAwesomeIcon icon={faEye} />
const closeEye = <FontAwesomeIcon icon={faEyeSlash} />
const [passwordShown, setPasswordShown] = useState(false);
let [email, setEmail] = useState("");
let [password, setPassword] = useState("");
const togglePasswordVisiblity = () => {
setPasswordShown(passwordShown ? false : true);
};
const onSubmit = (data) => {
console.log(data)
}
return (
<div className="page-container">
<div className="content-wrap">
<Nav />
<div className="div-login-form">
<h1 className="title">Login</h1>
<form className="login-form" onSubmit={handleSubmit(onSubmit)}>
<FormField
type="email"
standard="labeleffect"
value={email}
keys={'email'}
name="email"
effect={'effect_1'}
handleOnChange={(value) => setEmail(value)}
{...register("email")}
placeholder={'Enter Email'} />
<div className="input-password">
<div className="icon-eye">
<i onClick={togglePasswordVisiblity} className="icon"> {passwordShown ? eye : closeEye} </i>
</div>
<FormField
type={passwordShown ? "text" : "password"}
standard="labeleffect"
value={password}
keys={'password'}
name="password"
effect={'effect_1'}
handleOnChange={(value) => setPassword(value)}
{...register("password")}
placeholder={'Enter Password'} />
</div>
<button className="button-shop" type="submit">
Log in
</button>
</form>
</div>
</div>
<Footer />
</div>
);
}
export default Login;
You're not passing anything into your onSubmit function.
Rewrite it to something like this with your current setup:
onSubmit={() =>
handleSubmit(onSubmit({ email: email, password: password }))
}
Here's a minimal sandbox example
Aside
By the way, NPM is a package manager, not a component or element provider like you're referring to it by. Check out the useState docs for a good intro to states and React development.
My problem is when i send with react js axios post a request to the server i get req.body empty
index.js
const express = require('express');
const cors = require('cors');
const config = require('config');
const testRoutes = require('./routes/test');
const app = express();
const PORT = config.get('port') || 5000;
app.use(cors());
app.use(express.json({ extended: true }));
app.use('/api/test', testRoutes);
app.listen(PORT, () => console.log(`Сервер запустился на порте ${PORT}`));
form component
import React from 'react';
import { Link } from 'react-router-dom'
import './login-page.css';
const LoginPage = (props) => {
const { phone, password, inputControl, handlerLogin } = props;
return (
<div className="login-page">
<div className="container">
<div className="row">
<div className="col-left col-lg-6">
<div className="wrapper-col">
<h4>Войти</h4>
<div className="separator">
<hr />
<span>заполните форму</span>
<hr />
</div>
<form onSubmit={handlerLogin}>
<div className="mb-3">
<input className="form-control"
type="text"
name="phone"
placeholder="Телефон"
value={phone}
onChange={inputControl} />
</div>
<div className="mb-3">
<input className="form-control"
type="password"
name="password"
placeholder="Пароль"
value={password}
onChange={inputControl} />
</div>
<button className="btn btn-lg btn-login mb-2"
type="submit">Войти</button>
<Link to="/recovery">Забыли пароль?</Link>
</form>
</div>
</div>
<div className="col-right col-lg-6">
<div className="wrapper-col">
<h4>Нет аккаунта? Присоединяйтесь к нам!</h4>
<p>После регистрации у вас будет возможность как выполнять заказы, так и заказывать услуги на Yams.</p>
<Link to="/registration" className="btn">Зарегестрироваться</Link>
</div>
</div>
</div>
</div>
</div>
)
}
export default LoginPage;
handler
When i send via new FormData to the server i get an empty object
handlerLogin = (e) => {
e.preventDefault();
console.log('handlerLogin()');
const formData = new FormData(e.target);
axios.post('http://localhost:5000/api/test/', formData)
}
file routes
const { Router } = require('express');
const router = Router();
router.post('/', (req, res) => {
console.log(req.body); //req.body -> {}
})
module.exports = router;
handler
But when I send from a regular JSON object
handlerLogin = (e) => {
e.preventDefault();
console.log('handlerLogin()');
axios.post('http://localhost:5000/api/test/', {name: 'test1', surname: 'test2'});
}
I receive the sent data on the server, Works as it should
const { Router } = require('express');
const router = Router();
router.post('/', (req, res) => {
console.log(req.body); // req.body ---> {name: 'test1', surname: 'test2'}
})
module.exports = router;
Help solve this problem, I will be very grateful, thanks!
FormData requests (which support file uploads) send multipart formatted data, but the only body parsing middleware you have is setup for JSON formatted data.
You need something which can handle the type of body you are sending.
multer is probably the most popular middleware for handling multipart data.
You also must make sure that e.target is a form with successful controls in it. It could be fine, but we can’t see it so we can’t tell.