Reputation: 488
I've never really noticed this before; not sure if theres a bug in my code or if onChange always behaves this way, but I'm getting an input delay and am not sure how to resolve it. Heres an example of what I mean:
As you can see the console only prints the previous state which is a nuisance because that means to have the user log in they have to click the "Go" button twice for it to receive the correct state, even if the username and password has been correctly input.
My code is fairly straight forward:
const [state, setState] = useState<LoginStateType>(iLoginState)
const {username, password} = state
const handleChange = (event: ChangeEventType) => {
const {name, value} = event.target
setState({...state, [name]: value})
console.log(username)
}
{...}
<input type="text" name="username" value={username} onChange={handleChange}/>
<input type="text" name="password" value={password} onChange={handleChange}/>
Any help is appreciated, thanks!
Upvotes: 0
Views: 3567
Reputation: 488
What I ended up doing was perhaps a bit cumbersome but it gets the job done. Aside from the state (which is necessary for the useContext I have set up) I also set up two useRef constants:
const inputUserName = useRef<HTMLInputElement | null>(null)
const inputPassword = useRef<HTMLInputElement | null>(null)
{...}
<input type="text" name="username" ref={inputUserName} value={username} onChange={handleChange}/>
<input type={inputType as string} ref={inputPassword} name="password" value={password} onChange={handleChange}/>
So the full code I have is as follows:
//-------------ADMIN STATE-------------
const [state, setState] = useState<LoginStateType>(iLoginState)
const {username, password} = state
//-------------USE EFFECT-------------
//UseEffect: this is called when the context is set, I think
useEffect(() => {
//dispatch must be called before submit, I think because its an asynchronous call
dispatch(getAdminsRedux());
setContext(localStorage.getItem('user'))
if (context !== null){
navigate("/admin", {replace: true})
}
}, [setContext, context, dispatch, navigate]);
//-------------HANDLE CHANGE-------------
const handleChange = (event: ChangeEventType) => {
const {name, value} = event.target
setState({...state, [name]: value})
}
//-------------HANDLE LOGIN-------------
const handleLogin = async (event: MouseEvent) => {
event.preventDefault()
admins.forEach(async (admin) => {
if(admin.username === inputUserName.current!.value){
const comparedHash = compareHash(inputPassword.current!.value, admin.password)
if (comparedHash){
setContext(state.username)
localStorage.setItem('user', state.username)
}
}
});
}
Upvotes: 0
Reputation: 312
Since State Updates May Be Asynchronous.
With hooks, this can be achieved by
const [state, setState] = useState(/* ... */)
setState(/* ... */)
useEffect(() => {
// state is guaranteed to be what you want
}, [state])
Upvotes: 1