Hi I have created a login page using React-Typescript. User login with username and password then click the submit button HttpPost Request call to my backend. If my response status succeeded. My response information back to return my React application. That response data i need store and pass the data to another page. That page call the get request. in that getrequest parameter i will send the response data.
For ex:
User successfully logged in. Backend send to the response(userId,userName). Then Redirect the Home page.
My home page have Httpget request(fetch("http:localhost:8080/api/getuser"). I need to pass the userId and userName in http request like(fetch("http:localhost:8080/api/getuser?userId="+userId"&userName="+userName)
Login tsx file:
import React from 'react';
import { Redirect } from 'react-router-dom';
import { SyntheticEvent, useState } from 'react';
import { Link } from 'react-router-dom';
const { REACT_APP_API_ENDPOINT } = process.env;
const Login = (props: { setName: (name: string) => void }) => {
const [userName, setuserName] = useState('');
const [userid, setuserId] = useState('');
const [password, setPassword] = useState('');
const [redirect, setRedirect] = useState(false);
const submit = async (e: SyntheticEvent) => {
e.preventDefault();
const response = await fetch(`${REACT_APP_API_ENDPOINT}/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
userName,
password
})
});
const content = await response.json();
console.log(content);
setRedirect(true);
props.setName(content.userName);
setuserId(content.userId);
console.log(content.userId);
}
if (redirect) {
return <Redirect to="/" />
}
return (
<div>
<form onSubmit={submit} className="form-signin">
<h1 className="h3 mb-3 fw-normal">Please sign in</h1>
<div>
<input type="userName" className="form-control" placeholder="UserName" required
onChange={e => setuserName(e.target.value)} />
</div>
<div>
<input type="password" className="form-control" placeholder="Password" required
onChange={e => setPassword(e.target.value)} />
</div>
<button className="w-100 btn btn-lg btn-primary" type="submit">Log in</button>
</form>
</div>
);
};
export default Login;
App tsx file
import React, { Component } from 'react';
function Home() {
const { REACT_APP_API_ENDPOINT } = process.env;
const [name, setName] = useState('');
const [id, setId] = useState('');
useEffect(() => {
(
async () => {
const response = await fetch(`${REACT_APP_API_ENDPOINT}/getuser`, {
headers: { 'Content-Type': 'application/json' }
})
.then(function (response) {
console.log(response);
})
const content = await response;
//setName(content.name);
}
)();
});
return ();
export default Home;
There can be multiple ways of passing data from one component to another :
Using Props. You can use props to pass data from parent to child component. ...
|--- App.js
|---- ParentComponent
|----ChildComponent
Using React ContextAPI or State management library like Redux. ...
Using Props as Callback Function.
<Link
to={{
pathname: "/page",
data: data // your data array of objects
}}
>
//in /page
render() {
const { data } = this.props.location
return (
// render logic here
)
}
Okay. So, you want to send userId and userName from your Login component to Home component? You can send props from Login component via Redirect and access these props in Home component using useLocation hook.
//Login.jsx
<Redirect
to={{
pathname: "/",
state: { userId, userName }
}}
/>
//-------------------------------------
//App.jsx
import { useLocation } from 'react-router-dom';
const location = useLocation();
const { userId, userName } = location.state;
Related
I'm making a component that branches routing based on token existence.
I don't use the useEffect hook, but I keep getting an error about the useEffect hook. How would you like to solve it?
(It continues to be called and the number increments indefinitely.)
(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:38935:5)
at Router (http://localhost:3000/static/js/bundle.js:38992:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:37324:5)
at App
In the login component, after logging in, it was confirmed that the token is stored in the local storage, but it is immediately changed to undefined.
<App.js>
import './App.css';
import {BrowserRouter as Router, Route,Routes, Navigate} from 'react-router-dom';
import Todos from './Todos';
import Login from './Login';
function App() {
return(
<Router>
{!localStorage.getItem('token') ? <Navigate to ="/" /> : <Navigate to="/todo" />}
<Routes>
<Route path="/" element={<Login/>}></Route>
<Route path="/todo" element={<Todos/>}></Route>
</Routes>
</Router>
)
}
export default App;
<Login.js>
import './App.css';
import {useCallback, useState} from 'react';
import SignUpComponent from './SignUpComponent';
import axios from 'axios';
function Login() {
const [signUpState, setSignUpState] = useState(false);
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const [emailValidState, setEmailValidState] = useState(false)
const [passwordValidState, setPasswordValidState] = useState(false)
console.log(emailValidState, passwordValidState)
function controllSignUp(){
setSignUpState(!signUpState)
}
const emailCheck = useCallback((e) => {
const emailCurrent = e.target.value
setEmail(emailCurrent)
const emailRegex =
/^(([^<>()\[\].,;:\s#"]+(\.[^<>()\[\].,;:\s#"]+)*)|(".+"))#(([^<>()[\].,;:\s#"]+\.)+[^<>()[\].,;:\s#"]{2,})$/i
if (!emailRegex.test(emailCurrent)) {
setEmailValidState(false)
} else {
setEmailValidState(true)
}
}, [])
const passwordCheck = useCallback((e) => {
const passwordRegex = /^(?=.*[a-zA-Z])(?=.*[!##$%^*+=-])(?=.*[0-9]).{8,25}$/
const passwordCurrent = e.target.value
setPassword(passwordCurrent)
if (!passwordRegex.test(passwordCurrent)) {
setPasswordValidState(false)
} else {
setPasswordValidState(true)
}
}, [])
function callSignIn(){
let url = "https://pre-onboarding-selection-task.shop/auth/signin"
let data = {
"email": email,
"password": password
}
axios
.post(url, JSON.stringify(data), {
headers: {
"Content-Type": `application/json`,
},
})
.then((res) => {
localStorage.setItem('token', res.data.access_token)
})
return;
}
return (
<div className="App">
<div className ="SignIn">
<h1>LOGIN</h1>
<form className = "loginForm">
<label htmlFor="email">email</label>
<input
id="email"
type="email"
name="email"
value={email}
onChange={emailCheck}
placeholder="test#email.com"
/>
<label htmlFor="password">password</label>
<input
id="password"
type="password"
name="password"
value={password}
onChange={passwordCheck}
placeholder="****************"
/>
<button onClick={callSignIn} disabled={(emailValidState && passwordValidState)? false : true}>login</button>
</form>
<button onClick={controllSignUp}>signup</button><br/><br/>
{signUpState && <SignUpComponent/>}
</div>
</div>
);
}
export default Login;
<Todo.js>
import {useState} from 'react'
import axios from 'axios'
export default function Todos(){
const [todo, setTodo] = useState("")
const [id, setId] = useState("")
const [datas, setGetDatas] = useState([])
function listenTodo(e){
setTodo(e.target.value)
}
const token = localStorage.getItem('token')
console.log(token)
let url = "https://pre-onboarding-selection-task.shop/todos"
function createTodo(){
let data = {
"todo": todo
}
axios
.post(url, JSON.stringify(data), {
headers: {
"Content-Type": `application/json`,
"Authorization" : `Bearer ${token}`,
"withCredentials" : true
},
})
.then((res) => {
localStorage.setItem('token', res.data.access_token)
});
}
function getTodo(){
axios
.get(url, {
headers: {
"Authorization" : `Bearer ${token}`
},
})
.then((res) => {
setGetDatas(res.data)
});
}
/*
function deleteTodo(id){
axios
.get(url + `/id`, {
headers: {
"Authorization" : `Bearer ${token}`
},
})
.then((res) => {
setGetDatas(res.data)
});
}
*/
console.log(todo)
return(
<div className ="todoList">
<h1>TodoList</h1>
<div className = "todoTable">
<table>
<tr>
<td><strong>ID</strong></td>
<td><strong>Todo</strong></td>
</tr>
{datas.map((data)=>{
<tr>
<td>{data.id}</td>
<td>{data.todo}</td>
</tr>
})}
</table>
</div>
<div>
<input onChange={listenTodo} type="text" placeholder='input Todo'/>
<button onClick={createTodo}>input</button>
</div>
<div>
<button onClick={getTodo}>search</button>
</div>
</div>
)
}
I have a question regarding firebase auth best practices. Below is some simple code which handles user login. I want to know after the user logs in, what is the best / most efficient way of storing the user information in React. I have 3 options:
Storing in state the 'user' object which comes back in the .then
Storing in a context the 'user' object which comes back in the .then
Using the auth variable from firebase-config.js which comes with the currentUser object
Thanks
import React, { useState } from "react";
import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "../firebase-config";
import { useNavigate } from "react-router-dom";
const Login = () => {
const [loginEmail, setLoginEmail] = useState("");
const [loginPassword, setLoginPassword] = useState("");
const [currentUser, setCurrentUser] = useState({});
const navigate = useNavigate();
const handleLogin = () => {
signInWithEmailAndPassword(auth, loginEmail, loginPassword)
.then((user) => {
setCurrentUser(user);
navigate("/");
})
.catch((err) => {
console.log(err.code);
err.code === "auth/wrong-password"
? alert("Incorrect password")
: alert(err.code);
});
};
return (
<>
<div className="form-container">
<p>
email
<input
type="email"
onChange={(e) => {
setLoginEmail(e.target.value);
}}
/>
</p>
<p>
password
<input
type="password"
onChange={(e) => {
setLoginPassword(e.target.value);
}}
/>
</p>
<button onClick={handleLogin}>Login</button>
</div>
</>
);
};
export default Login;
i am using react-router-dom v6 this code generating above error message ..please help me to solve the error ... backend is working fine ..i think this error is coming from fronted .... it works with postman ..
i am following a older tutorial ... now i installed new version of react-router-dom ... please help me out
this is ResetPassword.js file
import React, { Fragment, useState, useEffect } from "react";
import "./ResetPassword.css";
import Loader from "../layout/Loader/Loader";
import { useDispatch, useSelector } from "react-redux";
import { clearErrors, resetPassword } from "../../actions/userAction";
import { useAlert } from "react-alert";
import MetaData from "../layout/MetaData";
import LockOpenIcon from "#material-ui/icons/LockOpen";
import LockIcon from "#material-ui/icons/Lock";
const ResetPassword = ({ history, match }) => {
const dispatch = useDispatch();
const alert = useAlert();
const { error, success, loading } = useSelector(
(state) => state.forgotPassword
);
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const resetPasswordSubmit = (e) => {
e.preventDefault();
const myForm = new FormData();
myForm.set("password", password);
myForm.set("confirmPassword", confirmPassword);
dispatch(resetPassword(match.params.token, myForm));
};
useEffect(() => {
if (error) {
alert.error(error);
dispatch(clearErrors());
}
if (success) {
alert.success("Password Updated Successfully");
history.push("/login");
}
}, [dispatch, error, alert, history, success]);
return (
<Fragment>
{loading ? (
<Loader />
) : (
<Fragment>
<MetaData title="Change Password" />
<div className="resetPasswordContainer">
<div className="resetPasswordBox">
<h2 className="resetPasswordHeading">Update Profile</h2>
<form
className="resetPasswordForm"
onSubmit={resetPasswordSubmit}
>
<div>
<LockOpenIcon />
<input
type="password"
placeholder="New Password"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<div className="loginPassword">
<LockIcon />
<input
type="password"
placeholder="Confirm Password"
required
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
</div>
<input
type="submit"
value="Update"
className="resetPasswordBtn"
/>
</form>
</div>
</div>
</Fragment>
)}
</Fragment>
);
};
export default ResetPassword;
And The backend code is here
export const resetPassword = (token, passwords) => async (dispatch) => {
try {
dispatch({ type: RESET_PASSWORD_REQUEST });
const config = { headers: { "Content-Type": "application/json" } };
const { data } = await axios.put(
`/api/v1/password/reset/${token}`,
passwords,
config
);
dispatch({ type: RESET_PASSWORD_SUCCESS, payload: data.success });
} catch (error) {
dispatch({
type: RESET_PASSWORD_FAIL,
payload: error.response.data.message,
});
}
};
Thank you
In react-router-dom#6 the Route component API changed significantly. There are no longer any route props (i.e. no match or history props) all replaced by React hooks. The history object was replaced by a navigate function via the useNavigate hook, and route path params are accessible via the useParams hook.
Example:
import { useNavigate, useParams } from 'react-router-dom';
const ResetPassword = () => {
const navigate = useNavigate(); // <-- access navigate function
const { token } = useParams(); // <-- access token path parameter
...
const resetPasswordSubmit = (e) => {
...
dispatch(resetPassword(token, myForm)); // <-- use token param here
};
useEffect(() => {
...
if (success) {
alert.success("Password Updated Successfully");
navigate("/login"); // <-- call navigate here
}
}, [dispatch, error, alert, navigate, success]);
I need to restrict links in react router by specific user roles (I have roles stored in token). What I'm trying to do now is:
send username & password through SignIn component to getTokens() function from custom useAuth hook on submit to then pass a boolean isModerator inside route value to ensure that the user have the required authorities for the link to show. In my case request is just not going to the server on form submit, probably because I misuse context api or react itself somehow.
So this is how my useAuth hook looks right now:
import React, { useState, createContext, useContext, useEffect } from "react";
import axios from "axios";
export const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const [authed, setAuthed] = useState(false);
const [moderator, setModerator] = useState(false);
const [accessToken, setAccessToken] = useState("");
const [refreshToken, setRefreshToken] = useState("");
const [authorities, setAuthorities] = useState([]);
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const signIn = async (e, username, password) => {
e.preventDefault();
const result = await getTokens(username, password);
if (result) {
console.log("User has signed in");
setAuthed(true);
}
};
const isModerator = async () => {
const result = await getAccessTokenAuthorities();
if (result) {
console.log("User is admin");
setModerator(true);
}
};
const getTokens = async (username, password) => {
const api = `http://localhost:8080/api/v1/public/signIn?username=${username}&password=${password}`;
const res = await axios.get(api, {
withCredentials: true,
params: {
username: username,
password: password,
},
});
const data = await res.data;
setAccessToken(data["access_token"]);
setRefreshToken(data["refresh_token"]);
console.log(data);
return accessToken, refreshToken;
};
const getAccessTokenAuthorities = async () => {
const api = `http://localhost:8080/api/v1/public/getAccessTokenAuthorities`;
const res = await axios.get(api, {
withCredentials: true,
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
const data = await res.data;
setAuthorities(data);
let vals = [];
authorities.forEach((authority) => {
vals.push(Object.values(authority));
});
const check = vals.filter((val) => val.toString() === "MODERATOR");
if (check.length > 0) return !isModerator;
console.log(authorities);
return isModerator;
};
return (
<AuthContext.Provider
value={{
authed,
setAuthed,
moderator,
setModerator,
getTokens,
getAccessTokenAuthorities,
username,
password,
setUsername,
setPassword,
}}
>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext);
And this is me trying to use AuthContext in SignIn component:
import React, { useContext, useEffect, useState } from "react";
import { useAuth } from "../hooks/useAuth";
import { AuthContext } from "../hooks/useAuth";
const SignIn = (props) => {
const auth = useAuth();
const userDetails = useContext(AuthContext);
return (
<>
<h1>Вход</h1>
<form
method="get"
onSubmit={(e) => auth.signIn(e)}
encType="application/json"
>
<label htmlFor="username">Имя пользователя</label>
<input
type="text"
id="username"
onChange={(e) => userDetails.setUsername(e.target.value)}
></input>
<label htmlFor="password">Пароль</label>
<input
type="password"
id="password"
onChange={(e) => userDetails.setPassword(e.target.value)}
></input>
Вход
<input type="submit"></input>
</form>
</>
);
};
SignIn.propTypes = {};
export default SignIn;
Here is how I set my AuthProvider in index.js:
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css"; import reportWebVitals from "./reportWebVitals";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Inventory from "./components/Inventory";
import SignIn from "./components/SignIn";
import { AuthProvider } from "./hooks/useAuth";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<AuthProvider>
<Routes>
<Route path="/"
element={<App />}>
</Route>
<Route path="api/v1/public/signIn"
element={<SignIn />}>
</Route>
<Route path="api/v1/moderator/inventory" element={<Inventory />} >
</Route>
</Routes>
</AuthProvider>
</BrowserRouter>
</React.StrictMode> );
reportWebVitals();
Thanks in advance.
You're creating 2 instances of context when you initialize 2 variables of it.
Both of these variables are behaving as separate instances of context. Its like when an object is initialized from a constructor.
All the methods you've passed to context Provider are available on const auth=useAuth(). Inside your Signin component, you're calling userDetails.setUsername() for changing value of username and to submit the form you're calling auth.signin.
You can simply use auth.setUsername(e.target.value) and auth.setPassword(e.target.value). For submitting form use auth.signin()
const SignIn = (props) => {
const auth = useAuth();
// const userDetails = useContext(AuthContext); No need to initialize this one
useEffect(() => {
// here in this log you will see all the methods are available from context provider
if (auth) console.log(auth);
}, [auth]);
return (
<>
<h1>Вход</h1>
<form
method="get"
onSubmit={(e) => auth.signIn(e)}
encType="application/json"
>
<label htmlFor="username">Имя пользователя</label>
<input
type="text"
id="username"
onChange={(e) => auth.setUsername(e.target.value)}
></input>
<label htmlFor="password">Пароль</label>
<input
type="password"
id="password"
onChange={(e) => auth.setPassword(e.target.value)}
></input>
Вход
<input type="submit"></input>
</form>
</>
);
};
export default SignIn;
I have a react application with redux. In the app there is a text field and a button. When the button is clicked an action creator is dispatched.
Here is an example of the component
import {useState} from "react";
import {useDispatch, useSelector} from "react-redux";
import updateEmail from "redux/actions/updateEmail";
const MyForm = () => {
const [email, setEmail] = useState("")
const dispatch = useDispatch()
const {saving, error} = useSelector(state => state.saveEmail)
if (saving) return <div>Please wait.....</div>
if (error) return <div>Something has gone wrong.....</div>
return (
<div className="container">
<p>Forgot Password</p>
<input
value={email}
onChange={e => setEmail(e.target.value)}
className="input is-large"
type="text"
placeholder="Email"
></input>
<a onClick={() => dispatch(updateEmail())} className="has-text-weight-bold">Login</a>
</div>
);
};
export default MyForm;
when the redux state saving, error changes, the UI re-renders. The state defines what the user is displayed.
In a NextJS application, how would I go about doing this without using redux.
What is the correct way without redux
for the client to make rest calls similar to above
the UI to re-render based on the state similar to above example
I don't really understand what the form is, is it for Login? I suppose it's for submitting Email for Password Reset. I commented you Answer too, so you can reconsider the Redux way for NextJS.
Anyway here is the proper way, which is the normal React way to do it in NextJS:
import { useState } from 'react';
import axios from 'axios';
// forget redux
// import {useDispatch, useSelector} from "react-redux";
// import updateEmail from "redux/actions/updateEmail";
const MyForm = () => {
const [email, setEmail] = useState('');
// 2 new states are created just for the form
// const { saving, error} = useSelector(state => state.saveEmail)
const [saving, setSaving] = useState(false);
const [error, setError] = useState(false);
// the dispatch (which has a function defined at another place)
// is replaced by a local function
// const dispatch = useDispatch()
const updateEmail = () => {
setSaving(true);
setError(false);
axios({
method: 'post',
url: `https://example.com/api/submit-email`,
headers: {
'Content-Type': 'application/json',
},
data: {
email,
},
})
.then(response => {
console.log('response login', response.data);
// NEXT STEP
})
.catch(err => {
console.log('login user error', err.response);
setSaving(false);
setError(true);
});
};
if (saving) return <div>Please wait.....</div>;
if (error) return <div>Something has gone wrong.....</div>;
return (
<div className="container">
<p>Forgot Password</p>
<input
value={email}
onChange={e => setEmail(e.target.value)}
className="input is-large"
type="text"
placeholder="Email"
/>
<a onClick={updateEmail} className="has-text-weight-bold">
Submit Email
</a>
</div>
);
};
export default MyForm;