Default value in input field lost after click - reactjs

So, i'm making this social network app and it has user profile. if user wants to update profile, eg. name, by opening modal EditUser, the old value of users name should be there, in input filed, and user needs to have opportunity to change/update that.
I used 'defaultValue', and there is it, in input field, but if i don't change anything in that field, just click 'update', it will be lost. updated value is empty string then, and not the value that is showing in that field. how can i fix this?
Also interested how to set as default user image. so, user has profile image, and on update if user changes only name, not the picture or something else, everything else should be the same, but photo is also like input text field lost.
here is what i tried:
MyProfile.tsx
import React, { useState, useEffect, useContext } from 'react'
import './myprofile.css'
import Axios from 'axios'
import SinglePost from '../single_post/SinglePost'
import { AppContext } from '../context/AppContext'
import UpdateProfile from '../modals/UpdateProfile'
function MyProfile() {
const [userInfo, setUserInfo] = useState({
firstName: '',
lastName: '',
userBio: 'Write something about yourself.',
userPhoto: ''
})
const [isEditOpen, setIsEditOpen] = useState(false)
const { userID, setUserID } = useContext(AppContext)
// open modal on click 'edit'
const editUser = () => {
setIsEditOpen(true)
}
// get user data
const storedToken = localStorage.getItem('token')
useEffect(() => {
const config = {
headers: { "x-auth-token": `${storedToken}` }
}
Axios
.get('/api/auth/user', config)
.then(res => {
console.log('response', res)
const user = res.data.user
setUserID(user._id)
setUserInfo({
firstName: user.first_name,
lastName: user.last_name,
userBio: user.user_bio,
userPhoto: user.profile_image
})
})
.catch(err => console.log(err))
}, [])
return (
<div className="profile-container">
<button className="btn-edit" onClick={editUser}>
<i className="fa fa-edit"></i>
</button>
<div className="user-info">
<div className="img-circular">
<img className="user-profile-img2" src={userInfo.userPhoto}></img>
</div>
<p className="user-name">{userInfo.firstName} {userInfo.lastName}</p>
<p className="about-user">{userInfo.userBio}</p>
</div>
<div className="user-posts">
<p className="my-posts-title">My Posts</p>
</div>
{isEditOpen && <UpdateProfile
userID={userID}
setIsEditOpen={setIsEditOpen}
isEditOpen={isEditOpen}
setUserInfo={setUserInfo}
userInfo={userInfo}
/>}
</div>
)
}
export default MyProfile
UpdateProfile.tsx
import React, { useState, useRef, useEffect } from 'react'
import { Modal, ModalHeader, ModalBody, ModalFooter, Button, FormGroup, Label, Input } from 'reactstrap'
import Axios from 'axios'
import '../user_profile/myprofile.css'
function UpdateProfile(props: any) {
const [firstNameUpdated, setFirstNameUpdated] = useState('')
const [lastNameUpdated, setLastNameUpdated] = useState('')
const [userBioUpdated, setUserBioUpdated] = useState('')
const inputNameRef = useRef<HTMLInputElement | any>(null)
useEffect(() => {
console.log(inputNameRef.current, props.userInfo.firstName)
inputNameRef.current && (inputNameRef.current.value = props.userInfo.firstName)
}, [])
// upload image
const [file, setFile] = useState('')
const [uploaded, setUploaded] = useState('')
const handleImageUpload = (e: any) => {
e.preventDefault();
setFile(e.target.files[0])
};
const onClickHandler = (e: any) => {
const formData = new FormData()
formData.append('fileImage', file)
Axios.post("/api/image", formData, {})
.then(res => {
//console.log(`UPLOADED: http://localhost:5000/${res.data.fileImage}`)
setUploaded(`http://localhost:5000/${res.data.fileImage}`)
})
.catch(err => console.log(err))
}
// update user
const updateUser = (e: any) => {
e.preventDefault()
props.setIsEditOpen(false)
const formData = new FormData()
formData.append('fileImage', file)
formData.append('first_name', firstNameUpdated)
formData.append('last_name', lastNameUpdated)
formData.append('user_bio', userBioUpdated)
const config: any = { header: { "Content-Type": "multipart/form-data" } }
Axios
.put(`/api/users/${props.userID}`, formData, config)
.then(res => {
const user = res.data
props.setUserInfo({
firstName: user.first_name,
lastName: user.last_name,
userBio: user.user_bio,
userPhoto: user.profile_image
})
})
.catch(err => console.log(err))
}
return (
<div>
{props.isEditOpen &&
<Modal isOpen={props.isEditOpen} toggle={() => props.setIsEditOpen(!props.isEditOpen)} backdrop="static">
<ModalHeader>Update your profile</ModalHeader>
<ModalBody>
<FormGroup>
<Label>Profile Image</Label>
<Input type="file" name="fileImage" onChange={handleImageUpload}></Input>
</FormGroup>
<Button onClick={onClickHandler} className="btn-upload-img">Upload file</Button>
<div className="inline">
{uploaded ? <img src={uploaded} style={{ width: "100px" }}></img> : <img src={props.userInfo.userPhoto} style={{ width: "100px" }}></img>}
</div>
<FormGroup>
<Label>First Name</Label>
<Input type="text" onChange={(e: any) => setFirstNameUpdated(e.target.value)} defaultValue={props.userInfo.firstName}></Input>
</FormGroup>
<FormGroup>
<Label>Last Name</Label>
<input type="text" onChange={(e: any) => setLastNameUpdated(e.target.value)} defaultValue={props.userInfo.lastName} ></input>
</FormGroup>
<FormGroup>
<Label>About me</Label>
<Input type="text" onChange={(e: any) => setUserBioUpdated(e.target.value)} defaultValue={props.userInfo.userBio}></Input>
</FormGroup>
</ModalBody>
<ModalFooter>
<Button color="success" onClick={updateUser} className="btn-update">Update</Button>
<Button color="danger" onClick={() => props.setIsEditOpen(false)}>Cancel</Button>
</ModalFooter>
</Modal>}
</div>
)
}
export default UpdateProfile
I'm just trying to get the old value in input field (which i did), and user can choose if wants to change that or not. if not, old value should stay in updated profile, but in my case, on click 'update' it is lost in user profile.

In UpdateProfile, you should initialise the states with the value you got in props and later they could change.
const [firstNameUpdated, setFirstNameUpdated] = useState(props.userInfo.firstName)
const [lastNameUpdated, setLastNameUpdated] = useState(props.userInfo.lastName)
const [userBioUpdated, setUserBioUpdated] = useState(props.userInfo.userBio)
Initialising the state could solve all your problem.

Related

how to fix issues with react datepicker

Below are 2 files that is expected to display details in a form, name, service, date, cost. The problem is that it doesn't display information entered in other input fields when I choose a future date. Whereas when I use the current date, it displays the information entered in other input fields as expected. Why is this the case please and how do i fix it?
import { useState, useEffect } from 'react';
import axios from 'axios';
const ConfirmBooking = () => {
//track state
const [data,setData] = useState([])
const Style = {
color: 'rgb(97, 113, 154)',
padding: '5px'
}
//GET data
useEffect(() => {
axios
.get('http://localhost:5000/api/bookings')
.then(res => {
console.log(res)
setData(res.data)
})
.catch(err => {
console.log(err)
})
}, [])
//DELETE data
const deleteHandler =(id) =>{
axios
.delete('http://localhost:5000/api/bookings/'+id)
.then(res => {
console.log(res.data);
}
)
.catch(error =>{
console.log(error)
})
}
if(!data?.length) return <div>loading...</div>
return (
<div className='bookings'>
<h4 style={Style}>Name:{" "}{data.at(-1).name}</h4>
<h4 style={Style} >Service:{" "}{data.at(-1).service}</h4>
<h4 style={Style} >Date:{" "}{data.at(-1).date}</h4>
<h4 style={Style} >Cost:{" "}{data.at(-1).cost}</h4><br></br>
<button className='Btn'>Edit</button>
<button className='Btn' onClick={ () => deleteHandler(data.at(-1))} >Delete</button>
</div>
)
}
export default ConfirmBooking;
import React, { useState } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom'
import DatePicker from 'react-datepicker';
import "react-datepicker/dist/react-datepicker.css";
const Form = () => {
const navigate = useNavigate();
const [myState, setMyState] = useState({
name: "",
service: "finance",
date: new Date(),
cost: "3$"
});
//event to handle all inputs except datepicker
const handleChange = (e)=> {
// const { name, value} = e.target;
const name = e.target.name;
const value = e.target.value
//to update the input myState
setMyState
({...myState, [name]: value });
}
const handleDateChange = (date) => {
setMyState({
date:date
})
}
const handleSubmit = (e) => {
e.preventDefault();
if (myState !== "") {
alert('booking success')
}
//Add data to database
axios.post('http://localhost:5000/api/bookings', myState)
.then(res => {
setMyState
(res.data);
console.log(res);
//redirect to another page
navigate('/ConfirmBooking')
})
.catch((error) => {
console.log(error)
})
}
return (
<form className='form' onSubmit={handleSubmit} >
<h2 className="headerForm">Create appointment</h2>
<div className="mb-3">
<label className="form-label">Name</label>
<input name='name' type="text" className="form-control" id="exampleFormControlInput1" value={myState.name} onChange={handleChange} />
<label className="form-label">Service</label>
<input name='service' type="text" className="form-control " id="exampleFormControlInput1" value={myState.service} onChange={handleChange} />
<label className="form-label"> Date</label>
<div>
<DatePicker
selected={myState.date}
onChange={handleDateChange}
startDate = {new Date()}
minDate={new Date()}
filterDate={date => date.getDay() !== 6 && date.getDay() !== 0}
/>
</div>
<label className="form-label">Cost</label>
<input name='cost' type="text" className="form-control" id="exampleFormControlInput1" value={myState.cost} onChange={handleChange} />
</div>
<button >Submit</button>
</form>
)
}
export default Form;
This method is changing the state without other properties:
...
const handleDateChange = (date) => {
setMyState({
date:date
})
}
...
If you want to change this property from state, you need to destructure previous value and change date.
const handleDateChange = (date) => {
setMyState({
...myState,
date:date
})
}

How to handle multiple select options submittion in react js?

I want to submit a form into mongoDB using nodejs API & reactJs. With the exception of the multiple select option, everything is operating as it should be.
Being new to react, I have no idea how to handle the multi select option's onChange method.
Here is what I've tried:
import React, { useState, useRef } from "react";
import { useForm } from "react-hook-form";
import { v4 as uuidv4 } from 'uuid';
import axios from "axios";
import Select from 'react-select';
export default function EventForm(props) {
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm();
const form = useRef();
const [loading, setLoading] = useState(false);
const [info, setInfo] = useState("");
const [analysis, setAnalysis] = useState("Undefined");
const [relatedEvent, setRelatedEvent] = useState([]);
const handleInfoChange = (e) => {
setInfo(e.target.value)
}
const handleAnalysisChange = (e) => {
setAnalysis(e.target.value)
}
const handleRelatedEvents = (e) => {
setRelatedEvent(e.target.value)
}
const relatedEventsData = props.data.map(opt => ({ label: opt.info, value: opt._id }));
const onSubmit = async () => {
setLoading(true);
const MySwal = withReactContent(Swal);
const eventData = {
UUID: uuidv4(),
info: info,
analysis: analysis,
relatedEvent: relatedEvent,
}
axios
.post(`${process.env.REACT_APP_PROXY}/api/events`, eventData)
.then((res) => {
console.log(res);
setLoading(false);
MySwal.fire(
"Success!",
"A new event has been saved successfully",
"success"
);
})
.catch((error) => {
console.log(error);
});
};
return (
<div className="panel-body">
<Form
ref={form}
onSubmit={handleSubmit(onSubmit)}
className="form-horizontal"
>
<div className="row">
<div className="col-lg-6">
<div className="mb-3">
<Form.Label>Info</Form.Label>
<Form.Control
type="text"
placeholder="Enter info..."
{...register("info", { required: true })}
value={info}
onChange={handleInfoChange}
/>
{errors.info && (
<ul className="parsley-errors-list filled" id="parsley-id-7" aria-hidden="false">
<li className="parsley-required">This value is required.</li>
</ul>
)}
</div>
</div>
<div className="col-lg-6">
<div className="mb-3">
<Form.Label>Related events</Form.Label>
<Select
options={relatedEventsData}
value={relatedEvent}
isMulti
onChange={handleRelatedEvents}
/>
</div>
</div>
<div className="col-lg-12">
<Button variant="primary" type="submit">
{loading ? "Saving..." : "Save"}
</Button>
</div>
</div>
</Form>
</div>
);
}
Could you please guide me how to make it work!
Thank you
you can make use of Select onChange event handler which passes the selected options as an array as argument ..
from that you can map over it to get the values as required
something as below:
const handleChange = (opts) => {
const selectedValues = opts.map((opt) => opt.value);
setSelectedValues(selectedValues);
};
Please check the working sample for better clarity 😉 -

How to fetch data for specific User in Firebase/React

Got my Landing page in here with hardcoded username / password into firebase db.
after successful login, I am redirected to the homepage. However, I am trying to figure out how to fetch the data for the specific logged in user. Currently, in my Firebase I have only 1 Collection which is Users and contains some documents any of the documents has their own fields it is all hardcoded for the sake of the test.
After the log in I am currently logging data but I only see the last added document. How do i attach the User to see its own data. I tried creating directly in firebase a document with the same UID as the logging user but the data that i am logging is still the last added document instead of the right for the specific user.
function LandingPage(props) {
const [showErrorModal, setShow] = useState(false);
const emailInputRef = useRef();
const passwordInputRef = useRef();
const navigate = useNavigate();
function sumbitForm(e) {
e.preventDefault();
const enteredEmail = emailInputRef.current.value;
const enteredPassword = passwordInputRef.current.value;
const url = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=AIzaSyCNBAxjeKNoAPPjBV0JW4vZ0QaTaOx9-L4';
fetch(url, {
method: 'POST',
body: JSON.stringify({
email: enteredEmail,
password: enteredPassword,
returnSecureToken: true,
}),
headers: {
'Content-Type': 'application/json',
},
}).then((res) => {
if (res.ok) {
navigate('/homepage')
} else {
setShow(true);
}
return res.json()
}).then((data) =>
console.log(data))
}
function handleClose() {
setShow(false)
}
return (
<div className='wrapper'>
<form onSubmit={sumbitForm}>
<h3>Login Here</h3>
<label htmlFor="username">Username</label>
<input type="text" placeholder="Sigh up with email" id="username" ref={emailInputRef} ></input>
<label htmlFor="password">Password</label>
<input type="password" placeholder="Password" id="password" ref={passwordInputRef}></input>
<button className='button' type="submit" typeof='submit' >Log In</button>
{showErrorModal ? <Modal show={showErrorModal} onHide={handleClose}
backdrop="static">
<Modal.Header>
<Modal.Title>Incorrect Username/Password</Modal.Title>
</Modal.Header>
<Modal.Body>
Please provide the correct credentials
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
</Modal.Footer>
</Modal> : null}
<div className='landingpage-logo'>
<img src={logo} className="landingpage-logo"></img>
</div>
</form>
</div>
)
}
export default LandingPage;
import React, { useEffect, useState } from "react";
import { getDatabase, ref, onValue } from "firebase/database";
import { db, firebase } from '../../firebase';
import 'firebase/compat/auth';
const HomeScreen = (props) => {
const [loadedData, setLoadedData] = useState([]);
const username = props.email.substring(0, props.email.indexOf('#'))
useEffect(() => {
readData();
}, [])
async function readData() {
db.collection('Users').get().then((querySnapshot) => {
querySnapshot.forEach(element => {
const incomingData = element.data();
setLoadedData(incomingData)
})
})
}
return (
<div className={styles['wrapper']}>
</div>
)
}
export default HomeScreen;
I created a simple project in react by using firebase to use crud proccessing.
https://github.com/celalaygar/web-push/tree/master/react-firebase-CRUD-example
in package.json->dependencies : "firebase": "^7.14.1"
in this file fetch data method is here.
https://github.com/celalaygar/web-push/blob/master/react-firebase-CRUD-example/src/components/main.component.js
fetchData = async () => {
const db = firebase.firestore();
const data = await db.collection("spell").get();
result = data.docs.map(doc => ({ ...doc.data(), id: doc.id }));
this.setState({ spell: result });
}

How do I retrieve an item data by id and pass it to another component in React16 with Hooks

I want to create an edit screen. I have a component called Task that looks like this
const Task = ({task}) => {
return (
<li>
<div>
<div>{task.text}</div>
{task.day}
</div>
<div className="icons">
<Link
to={`/edit/${task.id}`} >
<RiEdit2FillIcon />
</Link>
</div>
</li>
)
}
That goes to a parent component with a tasks.map() and then to the main component that will render the list of tasks. But from this component, I want to click on that Edit Icon and open an Edit screen that is already Routed like this <Route path='/edit/:id' component={EditTask}/> That EditTask component is what I am working on now
import React from 'react'
import {useState, useEffect} from 'react'
import { Link } from 'react-router-dom'
import Task from './components/Task'
const EditTask = () => {
const api ="http://localhost:5000"
const [tasks, setTasks] = useState([])
const [task, setTask] = useState([])
const [text, setText] = useState('')
const [day, setDay] = useState('')
const [reminder, setReminder] = useState(false)
const onSubmit = (e) => {
e.preventDefault()
updateData()
}
//Get Request
useEffect(() => {
const getTask = async () => {
const tasksFromServer = await fetchTask()
setTasks(tasksFromServer)
}
getTask()
},[])
const fetchTask = async (id) => {
const res = await fetch(`${api}/tasks/${id}`)
const data = await res.json()
console.log(data)
return data
}
//Update request
const updateData = async (id) => {
const taskToEdit = await fetchTask(id)
const updateTask = {
...taskToEdit,
reminder: !taskToEdit.reminder,
text: taskToEdit.text,
day: taskToEdit.day
}
const res = await fetch(`${api}/tasks/${id}`, {
method: 'PUT',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(updateTask)
})
const data = await res.json()
setTasks(
tasks.map((task) =>
task.id === id
? {
...task,
reminder: data.reminder,
text: data.text,
day: data.day
}
: task
)
)
}
return (
<div>
<header className='header'>
<h1>Edit</h1>
<Link to="/" className="btn btn-primary">Go Back</Link>
</header>
<form className="add-form" onSubmit={onSubmit}>
<Task task={task}/>
<div className="form-control">
<label>Task</label>
<input type="text" placeholder="Add Task" value={text} onChange={(e)=> setText(e.target.value)} />
</div>
<div className="form-control">
<label>Day & Time</label>
<input type="text" placeholder="Add Day & Time" value={day} onChange={(e)=> setDay(e.target.value)}/>
</div>
<div className="form-control form-control-check">
<label>Set Reminder</label>
<input type="checkbox" checked={reminder} value={reminder} onChange={(e)=> setReminder(e.currentTarget.checked)}/>
</div>
<input className="btn btn-block" type="submit" value="Save Task" />
</form>
</div>
)
}
export default EditTask
I'm a bit lost here. I can't figure out how to pass the ID from Task.js to EditTask.js and populate the form with the data form that ID.
Thanks in advance
You can get id in EditTask with useParams in "react-router
import { useParams } from "react-router";
const EditTask = () => {
const { id } = useParams();
}

New to react...state not updating on login

Looking for a gentle push in the right direction. Working on a react project and using hooks. Yes, have read documents, but not fully understanding yes.
The ask is about a login routine. Login form works, but does not reflect failed login state until repeat submission; so I am getting previous state, not current.
Tried useEffect...no change. Code follows, and appreciated any constructive feedback:
From the Login form
import React, { useState, useEffect, useRef } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Redirect } from 'react-router-dom'
import getAuthStatus from 'common/cyclone/auth/authenticated.status'
import {
authenticateByLogin,
authenticationSelector,
} from '../services/auth.service'
import Form from 'react-validation/build/form'
import Input from 'react-validation/build/input'
import CheckButton from 'react-validation/build/button'
const required = (value) => {
if (!value) {
return (
<div className="alert alert-danger" role="alert">
This field is required!
</div>
)
}
}
const Login = (props) => {
const form = useRef()
const checkBtn = useRef()
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [loading, setLoading] = useState(false)
const [errorMessage, setErrorMessage] = useState(null)
const dispatch = useDispatch()
const { session, hasErrors } = useSelector(authenticationSelector)
useEffect(() => {}, [session, hasErrors])
const onChangeUsername = (e) => {
const username = e.target.value
setUsername(username)
}
const onChangePassword = (e) => {
const password = e.target.value
setPassword(password)
}
const handleLogin = (e) => {
e.preventDefault()
setLoading(true)
form.current.validateAll()
if (checkBtn.current.context._errors.length === 0) {
dispatch(authenticateByLogin(username, password))
.then(() => {
setLoading(false)
if (hasErrors) {
setErrorMessage(session.error.message)
} else {
//props.history.push('/profile')
// window.location.reload()
}
})
.catch(() => {
setLoading(false)
})
} else {
setLoading(false)
}
}
if (session.success) {
//console.log(session.success)
return <Redirect to="/profile" />
}
if (getAuthStatus()) {
return <Redirect to="/profile" />
}
return (
<div className="col-md-12">
<div className="card card-container">
<img
src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
alt="profile-img"
className="profile-img-card"
/>
<Form onSubmit={handleLogin} ref={form}>
<div className="form-group">
<label htmlFor="username">Username</label>
<Input
type="text"
className="form-control"
name="username"
value={username}
onChange={onChangeUsername}
validations={[required]}
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<Input
type="password"
className="form-control"
name="password"
value={password}
onChange={onChangePassword}
validations={[required]}
/>
</div>
<div className="form-group">
<button className="btn btn-primary btn-block" disabled={loading}>
{loading && (
<span className="spinner-border spinner-border-sm"></span>
)}
<span>Login</span>
</button>
</div>
{hasErrors && (
<div className="form-group">
<div className="alert alert-danger" role="alert">
{errorMessage}
</div>
</div>
)}
<CheckButton style={{ display: 'none' }} ref={checkBtn} />
</Form>
</div>
</div>
)
}
export default Login
From the auth slice:
/** Third Party Libraries */
import { createSlice } from '#reduxjs/toolkit'
import qs from 'qs'
/**Axios Wrapper...nothing fancy here*/
import CycloneAPIInstance from 'common/cyclone/api/api.client'
import CycloneConfig from 'config/base'
/** Main API Server URL */
const API_URL = CycloneConfig.API_URL
const session = JSON.parse(localStorage.getItem('authentication'))
/** Define Initial State */
export const initialState = session
? {
hasErrors: false,
session: session,
}
: {
hasErrors: false,
session: [],
}
/** Define Slice */
const authenticationSlice = createSlice({
name: 'authentication',
initialState,
reducers: {
authenticateUser: (state) => {
state.hasErrors = false
},
authenticateUserSuccess: (state, { payload }) => {
state.hasErrors = false
state.session = payload
console.log(state.session)
},
authenticateUserFailure: (state, { payload }) => {
state.hasErrors = true
state.session = payload
},
deauthenticateUser: (state) => {
state.session = []
},
},
})
export const {
authenticateUser,
authenticateUserSuccess,
authenticateUserFailure,
deauthenticateUser,
} = authenticationSlice.actions
export const authenticationSelector = (state) => state.authentication
export default authenticationSlice.reducer
export function authenticateByLogin(user_name, user_password) {
let requestBody = {
user_name: user_name,
user_password: user_password,
}
let config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
}
return async (dispatch) => {
dispatch(authenticateUser())
try {
const response = await CycloneAPIInstance.post(
API_URL + 'auth/login',
qs.stringify(requestBody),
config
)
//console.log(response.data.content)
localStorage.setItem('session', JSON.stringify(response.data.content))
dispatch(authenticateUserSuccess(response.data.content))
} catch (error) {
//console.log(JSON.stringify(error.response.data))
dispatch(authenticateUserFailure(error.response.data))
}
}
}
export function deauthenticateByLogout() {
return async (dispatch) => {
dispatch(deauthenticateUser())
localStorage.removeItem('session')
}
}
Try to set the message when hasError change
useEffect(()=> {
if(hasErrors) {
setErrorMessage(session.error.message)
}
}, [hasErrors]);
This is quite some code so I just skipped through to fix the problem and not pick everything apart. My best guess is this part:
dispatch(authenticateByLogin(username, password))
.then(() => {
setLoading(false)
if (hasErrors) {
setErrorMessage(session.error.message)
} else {
//props.history.push('/profile')
// window.location.reload()
}
})
.catch(() => {
setLoading(false)
})
Here you execute the async authentication and then do thing based on "hasError". This "hasError" comes from a hook. We (or at least I) have no clear idea how this is managed. Thing is you cant be 100% sure that hasError is really trustworthy at the point you check it in the then-block. The hook might run just after the next render, which explains why you see the previous state, not the actual one.
Best guess would be to use the response from that async call, because there should be one => authenticate.then((response) => if(response.hasError) ...)
With this check you can set your own error state and your component should be up-to-date
Let me know if this fixes your error.

Resources