React.js, How to fetch the properties in a URL pathname? - javascript

I'm trying to fetch the uid and token through the URL pathname using match in my React app. But I got error:
Uncaught TypeError: n is undefined
and this is my code snippet:
const ResetPasswordConfirm = ( {match, reset_password_confirm} ) => {
...
const onSubmit = e=> {
e.preventDefault();
const uid = match.params.uid;
const token = match.params.token;
reset_password_confirm(uid, token, new_password, re_new_password);
setRequestSent(true);
};
};
According to this thread: https://stackoverflow.com/questions/70609785/uncaught-typeerror-match-is-undefined#:~:text=react%2Drouter%2Ddom%20v5,render%20or%20children%20prop%20functions.
It says it might have something to do with the version of react router, so I tried to use useParams(), but I found it hard to implement it...
I also tried to use matchPath, but I can find few examples.
Can anybody help me with this issue please?
Update:
react-router-dom version: 6.8.0
ResetPasswordConfirm is running in my container package.
import React, { useState } from "react";
import { Navigate, useParams } from 'react-router-dom';
import { connect } from 'react-redux';
import { reset_password_confirm } from '../actions/auth';
const ResetPasswordConfirm = ( {match, reset_password_confirm} ) => {
const [requestSent, setRequestSent] = useState(false);
const [formData, setFormData] = useState({
new_password: '',
re_new_password: ''
});
const { new_password, re_new_password } = formData;
const onChange = e => setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = e=> {
e.preventDefault();
const uid = match.params.uid;
const token = match.params.token;
reset_password_confirm(uid, token, new_password, re_new_password);
setRequestSent(true);
};
// Is the user sending the request?
// Redirect them to the home page
if (requestSent) {
return <Navigate to='/'/>
}
return (
<div className="container mt-5">
<form onSubmit={e => onSubmit(e)}>
{/* <div className="form-group">
<input className="form-control" type="email" placeholder="Email" name="email" value={email} onChange={e => onChange(e)} required></input>
</div>
<div className="form-group">
<input className="form-control" type="password" placeholder="Password" name="password" value={password} onChange={e => onChange(e)} minLength='6' required></input>
</div>
<button className="btn btn-primary" type="submit">Login</button> */}
<div className="form-group">
<label htmlFor="exampleInputPassword1">Password</label>
<input
type="password"
className="form-control"
id="exampleInputPassword1"
placeholder="New Password"
name="new_password"
value={new_password}
onChange={e => onChange(e)}
minLength='6'
required></input>
</div>
<div className="form-group">
<label htmlFor="exampleInputPassword1">Password</label>
<input
type="password"
className="form-control"
id="exampleInputPassword1"
placeholder="Confirm New Password"
name="re_new_password"
value={re_new_password}
onChange={e => onChange(e)}
minLength='6'
required></input>
</div>
<button type="submit" className="btn btn-primary">Reset Password</button>
</form>
</div>
);
};
export default connect(null, { reset_password_confirm }) (ResetPasswordConfirm);
Sorry for the lo-fi question. I will try to do better.
I tried to use useParams to fetch my uid
const onSubmit = e => {
...
let{uid} = useParams()
}

There are no longer route props in react-router-dom routed components, i.e. there is not any injected match prop. You'll use the useParams hook to access the route path params in RRDv6. You can't use React hooks in nested callbacks, they must be called in the function body of a React component or in custom React hooks. Use the useParams hook in the component body and destructure the uid and token path params. Since you are using hooks you may as well also import and use the useNavigate hook and issue the navigation action at the end of the form's onSubmit handler instead of enqueueing a state update.
import React, { useState } from "react";
import { useParams, useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { reset_password_confirm } from '../actions/auth';
const ResetPasswordConfirm = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const { uid, token } = useParams();
const [formData, setFormData] = useState({
new_password: '',
re_new_password: ''
});
const onChange = e => setFormData(formData => ({
...formData,
[e.target.name]: e.target.value
}));
const onSubmit = e => {
e.preventDefault();
const { new_password, re_new_password } = formData;
dispatch(reset_password_confirm(uid, token, new_password, re_new_password));
navigate("/");
};
return (
...
);
};
export default ResetPasswordConfirm;

Related

How to open different page from function React JS

I have two forms.
Login.jsx:
import React, {Fragment, useState } from "react";
import axios from "axios";
export const Login = (props) => {
const [user, setUser] = useState('');
const [pass, setPass] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
const data = {
KorisnickoIme: user,
Lozinka: pass
};
const url ='https://localhost:44357/api/Fin/Login';
axios.post(url, data).then((result)=>{
alert(result.data);
}).catch((error)=>{
alert(error);
})
};
return (
<Fragment>
<div className="auth-form-container">
<h2>Пријава</h2>
<form className="login-form" onSubmit={handleSubmit}>
<label htmlFor="user">Корисничко ме</label>
<input value ={user} onChange ={(e) => setUser(e.target.value)}placeholder="korisnicko_ime" id="user" name="user" required/>
<label htmlFor="email">Лозинка</label>
<input
value={pass}
onChange={(e) => setPass(e.target.value)}
type="password"
placeholder="********"
></input>
<button type="submit">Пријави се</button>
</form>
<button
className="link-btn"
onClick={() => props.onFormSwitch("register")}
>
Немаш налог? Региструј се овде.
</button>
</div>
</Fragment>
);
};
and Register.jxs:
import React, {Fragment, useState} from "react";
import axios from "axios";
import { ProfileSetUp } from './ProfileSetUp';
export const Register = (props) => {
const [email, setEmail] = useState('');
const [pass, setPass] = useState('');
const [name, setName] = useState('');
const [user, setUser] = useState('');
const [lastname, setLastname] = useState('');
const [checkPass, setCheckPass] = useState('');
const handleSubmit = (e) => {
if(pass==checkPass){
e.preventDefault();
const data = {
KorisnickoIme:user,
Ime: name,
Prezime: lastname,
Email: email,
Lozinka: pass
};
const url ='https://localhost:44357/api/Fin/Registration';
axios.post(url, data).then((result)=>{
alert(result.data);
}).catch((error)=>{
alert(error);
})
}else{
alert("Лозинке се не поклапају");
}
}
return(
<Fragment>
<div className="auth-form-container">
<h2>Регистрација</h2>
<form className="reg-form" onSubmit={handleSubmit}>
<label htmlFor="name">Име</label>
<input value ={name} onChange ={(e) => setName(e.target.value)}placeholder="Унесите Ваше име" id="name" name="name" required/>
<label htmlFor="lastname">Презиме</label>
<input value ={lastname} onChange ={(e) => setLastname(e.target.value)}placeholder="Унесите Ваше презиме" id="lastname" name="lastname" required/>
<label htmlFor="email">Е-маил</label>
<input value ={email} onChange ={(e) => setEmail(e.target.value)}type="email" placeholder="vasmail#fink.com" id="email" name="email" required/>
<label htmlFor="user">Корисничко ме</label>
<input value ={user} onChange ={(e) => setUser(e.target.value)}placeholder="Унесите Ваше korisnicko_ime" id="user" name="user" required/>
<label htmlFor="password">Лозинка</label>
<input value ={pass} onChange ={(e) => setPass(e.target.value)}type="password" placeholder="********" id="password" name="password" required/>
<label htmlFor="checkPass">Потврдите лозинку</label>
<input value ={checkPass} onChange ={(e) => setCheckPass(e.target.value)}type="password" placeholder="********" id="checkPass" name="checkPass" required/>
<button type="submit">Региструј се</button>
</form>
<button className="link-btn" onClick={() => props.onFormSwitch('login')}>Имате налог? Пријавите се.</button>
</div>
</Fragment>
)
}
/* */
After registering I want to send user to Login form but I am not sure how should I do it. Here is App.js just in case:
import React, {useState} from 'react';
import './App.css';
import { Register } from './Register';
import { Login } from './Login';
import { ProfileSetUp } from './ProfileSetUp';
function App() {
const [currentForm, setCurrentForm] = useState('login');
const toggleForm = (formName) => {
setCurrentForm(formName);
}
return (
<div className="App">
{
currentForm === "login" ? <Login onFormSwitch={toggleForm} /> : <Register onFormSwitch={toggleForm} />
}
</div>
);
}
export default App;
I am not sure how React page is represented so I am not sure how to use window.open() etc.
I followed one tutorial where is shown how to make this toggle switch function, which I like but I think that will make me troubles with other pages.
You can use the react-router package to link between different pages and pass data. Here is the documentation for the package https://reactrouter.com/en/main.
If you don't want to navigate to different components using routing, you could just use state variables to show/hide components included in a single parent component.

xhr.js:220 POST http://localhost:3000/EShop/register 400 (Bad Request)

Trying to POST request to send data to database but it always shows 400 bad request.
The AuthReducer file is as follow. Data is not getting posted when done in Frontend but its properly working when tested in postman api.
export const Register = (username, email , password) => async(disptach) => {
try{
disptach({type:REGISTER_USER_REQUEST})
const config = {
Headers:{
'Content-Type':'application/json'
}
}
const { data } = await axios.post('/EShop/register', {username ,email , password} , config)
disptach({
type:REGISTER_USER_SUCCESS,
payload:data.user
})
}catch(error){
disptach({
type:REGISTER_USER_FAIL,
payload : error.response.data.message
})
}
}
The register form is as follow..
import React, { useState, useEffect } from "react";
import { Link, useNavigate } from "react-router-dom"
import { useSelector, useDispatch } from "react-redux"
import Loader from "./loader";
import { Register } from "../actions/UserAction";
import "../css-files/Account.css"
export default function register() {
const [email, setemail] = useState('');
const [password, setpassword] = useState('');
const [username, setusername] = useState('');
const disptach = useDispatch();
const navigate = useNavigate();
const { isAuthenticated, error, loading } = useSelector(state => state.user)
useEffect(() => {
if (isAuthenticated) {
navigate('/account/login')
}
}, [disptach, isAuthenticated])
const SubmitRegisterHandler = (e) => {
e.preventDefault()
disptach(Register(username, email, password))
}
return (
<div id="Account_container">
{loading ?
<Loader />
:
<div id="wrapper">
<div id="Wrap_First">
<img src="https://res.cloudinary.com/dqxozrie1/image/upload/v1659935744/eshop/online-registration-sign-up_gfb2gs.webp" />
</div>
<div id="Wrap_Second">
<div id="login">
<h2>Create New Account</h2>
<form onSubmit={SubmitRegisterHandler}>
<input
required
type="text"
placeholder="Username"
value={username}
onChange={(e) => { setusername(e.target.value) }}
/>
<input
required
type="email"
placeholder="Email"
value={email}
onChange={(e) => { setemail(e.target.value) }}
/>
<input
required
type="password"
placeholder="Password"
value={password}
onChange={(e) => { setpassword(e.target.value) }}
/>
<button>Register</button>
</form>
<p id="existing_acc"><Link to="/account/login">Already have an account !</Link></p>
</div>
</div>
</div>
}
</div>
);
}
It gives 400 bad request always. Please help me how to resolve this issue.

useNavigate hook called inside useEffect causing infinite loop

i am using the useNavigate hook inside of react to direct users to a home page after successful login. everything i've read online suggests that i should use the useNavigate hook inside of a useEffect block, but when i do so, it triggers an infinite loop: Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
the odd thing is, though, that the warning only seems to occur after logging in for a second time. what i mean is that it will work on the first login after starting the server & client, but logging in a second, third, etc. time results in a Maximum update depth exceeded warning.
i use the useNavigate hook in two separate files, a login for users and a login for admin, both of which are below.
for further clarification on the issue arising only on the second login and beyond, it occurs regardless of whether i log in as admin or as a user. for instance, if my first login is as an admin, the Maximum update depth exceeded warning will occur regardless of whether my next login is as a user or as an admin. the same is true if my first login is as a user.
what i've tried so far:
removing navigate as from the dependency arrays (results in same warning)
removing the useEffect blocks (results in warnings to put the useNavigate hook inside of a useEffect hook. the login functionality breaks)
removing the dependency array altogether (results in the same warning)
the error when i login as user:
react-dom.development.js:86 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
at Navigate (http://localhost:3000/static/js/bundle.js:42950:5)
at Routes (http://localhost:3000/static/js/bundle.js:43067:5)
at div
at Router (http://localhost:3000/static/js/bundle.js:43000:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:41809:5)
at App
the error when i login as admin:
react-dom.development.js:86 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
at Navigate (http://localhost:3000/static/js/bundle.js:42950:5)
at Routes (http://localhost:3000/static/js/bundle.js:43067:5)
at div
at Router (http://localhost:3000/static/js/bundle.js:43000:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:41809:5)
at App
Login.jsx
import { useState, useEffect } from "react";
import axios from "axios";
import { Link, useNavigate} from "react-router-dom";
const Login = () => {
const navigate = useNavigate();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
useEffect(() => {
if (localStorage.getItem("authToken")) {
navigate("/home");
}
}, [navigate]);
const loginHandler = async (e) => {
e.preventDefault();
const config = {
header: {
"Content-Type": "application/json",
},
};
try {
const { data } = await axios.post("/api/auth/login", { email, password }, config);
localStorage.setItem("authToken", data.token);
navigate("/home");
} catch (error) {
setError(error.response.data.error);
setTimeout(() => {
setError("");
}, 5000);
}
};
return (
<div className="login-">
<form onSubmit={loginHandler} className="login-__form">
<h3 className="login-__title">Login</h3>
{error && <span className="error-message">{error}</span>}
<div className="form-group">
<label htmlFor="email">Email:</label>
<input
type="email"
required
id="email"
placeholder="Email address"
onChange={(e) => setEmail(e.target.value)}
value={email}
tabIndex={1}
/>
</div>
<div className="form-group">
<label htmlFor="password">
Password:{" "}
{/* <Link to="/forgotpassword" className="login-__forgotpassword">
Forgot Password?
</Link> */}
</label>
<input
type="password"
required
id="password"
autoComplete="true"
placeholder="Enter password"
onChange={(e) => setPassword(e.target.value)}
value={password}
tabIndex={2}
/>
</div>
<button type="submit" className="btn btn-primary">
Login
</button>
<span className="login-__subtext">
Don't have an account? <Link to="/register">Register</Link>
</span>
</form>
</div>
);
};
export default Login;
AdminLogin.jsx
import { useState, useEffect } from "react";
import axios from "axios";
import { Link, useNavigate} from "react-router-dom";
const AdminLogin = () => {
const navigate = useNavigate();
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
useEffect(() => {
if (localStorage.getItem("adminToken")) {
navigate("/admin/home");
}
}, [navigate]);
const adminLoginHandler = async (e) => {
e.preventDefault();
const config = {
header: {
"Content-Type": "application/json",
},
};
try {
const { data } = await axios.post("/api/admin/login", { username, password }, config);
localStorage.setItem("adminToken", data.token);
navigate("/admin/home");
} catch (error) {
setError(error.response.data.error);
setTimeout(() => {
setError("");
}, 5000);
}
};
return (
<div className="login-">
<form onSubmit={adminLoginHandler} className="login-__form">
<h3 className="login-__title">admin login</h3>
{error && <span className="error-message">{error}</span>}
<div className="form-group">
<label htmlFor="username">Username:</label>
<input
type="username"
required
id="username"
placeholder="Username"
onChange={(e) => setUsername(e.target.value)}
value={username}
tabIndex={1}
/>
</div>
<div className="form-group">
<label htmlFor="password">
Password:{" "}
{/* <Link to="/forgotpassword" className="login-__forgotpassword">
Forgot Password?
</Link> */}
</label>
<input
type="password"
required
id="password"
autoComplete="true"
placeholder="Enter password"
onChange={(e) => setPassword(e.target.value)}
value={password}
tabIndex={2}
/>
</div>
<button type="submit" className="btn btn-primary">
Login
</button>
<span className="login-__subtext">
Here by mistake? <Link to="/login">Login</Link>
</span>
</form>
</div>
);
};
export default AdminLogin;
it was asked in a comment, so i've also included Private.jsx (user home page) Admin.jsx (admin home page), though i don't think the issue is in either of these files.
Private.jsx
import { useState, useEffect } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";
const Private = () => {
const [error, setError] = useState("");
const [privateData, setPrivateData] = useState("");
const navigate = useNavigate();
const handleLogout = () => {
localStorage.removeItem('authToken');
navigate('/login');
console.log('logged out successfully');
}
return error ? (
<span className="error-message">{error}</span>
) : (
<div>
you're in the private route
<button onClick = {handleLogout}>Logout</button>
</div>
);
};
export default Private;
Admin.jsx
import { useNavigate } from 'react-router-dom';
export default function Admin() {
const navigate = useNavigate();
const handleLogout = () => {
localStorage.removeItem('adminToken');
navigate('/admin/login');
console.log('logged out successfully');
}
return (
<>
<div>ADMIN ROUTE UNLOCKED</div>
<button onClick = {handleLogout}>Logout</button>
</>
)
}
You need to listen for changes in your localStorage. Try this:
const checkAuth = () => {
if (localStorage.getItem("authToken")) {
navigate("/home");
}
}
useEffect(() => {
window.addEventListener("storage", checkAuth);
return () => {
window.removeEventListener("storage", checkAuth)
}
}, []);

Saving API response in React Context API and Redirect

In my login page after getting the email and password, I sent them through Axios post request to validate and generate a JWT web token and with that token I'm calling another Axios get request to fetch some data (packs). To do this I have used chaining and all these are happening in handleSubmit. I've also used context api to save all the API response and later use it on different pages. But after submitting the form data, I'm getting the response back in console log but the packs are not set as payload which I've called through dispatch in the second Axios request. Though the loggedIn is getting set to true but packs is returning undefined. Where it should've contained an array of 3 objects. I've also used Redirect from react-router-dom and if the loggedIn is true (which it is after submitting the form) it should take me to the homepage or {/}. It is also not working. The API Response after clicking submit
Login.js
const [{ packs, loggedIn }, dispatch] = useAppContext();
console.log(packs);
console.log(loggedIn);
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
const data = {
email: email,
password: password,
};
axios
.post("https://playtoshi.totafantasy.com/api/auth/login", data)
.then((res) => {
localStorage.setItem("token", res.data.token);
return axios.get("https://playtoshi.totafantasy.com/api/packs").then(
(res) => console.log(res),
dispatch({
type: "GET_DATA",
packs: res.data.packs,
loggedIn: true,
})
);
})
.catch((err) => console.log(err));
if (loggedIn) return <Redirect to={"/"} />;
};
return (
<div className="login__container">
<form className="login__form" onSubmit={handleSubmit}>
<h3>Sign In</h3>
<div className="form-group">
<label>Email address</label>
<input
type="email"
className="form-control"
placeholder="Enter email"
required
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className="form-group">
<label>Password</label>
<input
type="password"
className="form-control"
placeholder="Enter password"
required
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<div className="form-group">
<div className="custom-control custom-checkbox">
<input
type="checkbox"
className="custom-control-input"
id="customCheck1"
style={{ marginRight: "5px" }}
/>
<label className="custom-control-label" htmlFor="customCheck1">
Remember me
</label>
</div>
</div>
<button type="submit" className="btn btn-primary btn-block">
Submit
</button>
<p className="forgot-password text-right">
Forgot password?
</p>
</form>
</div>
);
}
export default Login;
Reducer.js
export const initialState = {
packs: [],
loggedIn: false,
};
export const reducer = (state, action) => {
switch (action.type) {
case "GET_DATA":
return {
...state,
packs: action.packs,
loggedIn: true,
};
default:
return { ...state };
}
};
Context.js
import React, { createContext, useContext, useReducer } from "react";
export const AppContext = createContext();
export const Context = ({ initialState, reducer, children }) => {
return (
<AppContext.Provider value={useReducer(reducer, initialState)}>
{children}
</AppContext.Provider>
);
};
export const useAppContext = () => useContext(AppContext);

I am passing in props but i cant see them

So I am passing in some data that i have saved in a state. I am then trying to pass that information as props on to another component. However, when I console.log it shows as undefined.
Here is the page i am passing information from:
import React, { useState } from 'react'
import { Link } from 'react-router-dom'
import axios from 'axios'
import IpContext from '../../IpContext'
import { useContext } from 'react';
import ReactDOM from 'react-dom';
import PostIssues from '../Trainee/PostIssues/PostIssues';
const LoginPage = props => {
const [userDetails, setuserDetails] = useState([]);
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [memberType, setMemberType] = useState("");
const getLogin = (e) => {
e.preventDefault();
if (memberType === "trainee") {
axios.get("http://" + ip + "/trainee/findByUsername/" + username)
.then(response => {
setuserDetails(response.data);
console.log(userDetails)
console.log(response.data.id);
}).catch(error => {
console.log(error)
});
} else {
console.log("ignore")
}
}
const validate = (e) => {
if (userDetails.username === username && userDetails.password === password) {
props.history.push("/postIssue");
// userDetails[0].map((issue) => (
<PostIssues
// number={number}
userDetails={userDetails}
/>
}
else {
e.preventDefault();
ReactDOM.render(<p style={{ color: "red" }}>Username/Password wrong</p>, document.getElementById('failed-message'));
}
}
return (
<>
<div className="loginDiv">
<h1 className="loginHeading">Login</h1>
<div>
<form className="ml-3" id="loginForm" onSubmit={validate}>
<input name="username" className="loginInput" type="text" id="username" placeholder="Enter your username" onChange={e => setUsername(e.target.value)} required></input> <br></br>
<input name="password" className="loginInput" type="password" id="password" placeholder="Enter your password" onChange={e => setPassword(e.target.value)} required></input> <br></br>
<select defaultValue="" name="traineeTrainer" onInput={e => setMemberType(e.target.value)} onChange={getLogin} >
<option value="" disabled hidden >Position</option>
<option value="trainer">Trainer</option>
<option value="trainee">Trainee</option>
</select>
<button className="btn btn-primary" id="loginButton" type="submit">Login</button>
<div>
<Link to="/createAccount">
<button style={{ backgroundColor: "darkred" }} className="btn btn-primary" id="signUpButton" type="button">Create an account</button>
</Link>
</div>
</form>
</div>
</div>
{/* Login failed will appear here */}
<div id="failed-message"></div>
</>
)
}
export default LoginPage
And this is where i want to receive information:
import React, {useState, useEffect} from 'react'
import axios from 'axios'
import Issue from '../../Trainer/Issue';
import IpContext from '../../../IpContext'
import { useContext } from 'react';
const PostIssues = props => {
console.log(props.userDetails.username);
return(
)
}
export default PostIssues;
When I run this on the browser I get and error which says
"TypeError: Cannot read property 'username' of undefined".
Why is it undefined if i am passing it as props?
Thanks in advance!
You're not actually returning anything, even though you have a return() in there. Try return(null) and read this answer to see why.
Additionally, I would recommend you try to debug this by using the developer tools in your browser. The React tools are quite handy and they allow you to inspect props and state.
Try rendering props.userDetails.username in a <div> inside your return statement to see the page render the component.

Categories